cec: fix handler init
[deb_libcec.git] / src / lib / implementations / CECCommandHandler.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 "CECCommandHandler.h"
34 #include "../devices/CECBusDevice.h"
35 #include "../devices/CECAudioSystem.h"
36 #include "../devices/CECPlaybackDevice.h"
37 #include "../CECProcessor.h"
38
39 using namespace CEC;
40 using namespace std;
41
42 CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice) :
43 m_busDevice(busDevice),
44 m_processor(m_busDevice->GetProcessor()),
45 m_iTransmitTimeout(CEC_DEFAULT_TRANSMIT_TIMEOUT),
46 m_iTransmitWait(CEC_DEFAULT_TRANSMIT_WAIT),
47 m_iTransmitRetries(CEC_DEFAULT_TRANSMIT_RETRIES),
48 m_bHandlerInited(false)
49 {
50 }
51
52 CCECCommandHandler::~CCECCommandHandler(void)
53 {
54 m_condition.Broadcast();
55 }
56
57 bool CCECCommandHandler::HandleCommand(const cec_command &command)
58 {
59 bool bHandled(true), bHandlerChanged(false);
60
61 CStdString strLog;
62 strLog.Format(">> %s (%X) -> %s (%X): %s (%2X)", m_processor->ToString(command.initiator), command.initiator, m_processor->ToString(command.destination), command.destination, m_processor->ToString(command.opcode), command.opcode);
63 m_busDevice->AddLog(CEC_LOG_NOTICE, strLog);
64
65 m_processor->AddCommand(command);
66
67 switch(command.opcode)
68 {
69 case CEC_OPCODE_REPORT_POWER_STATUS:
70 HandleReportPowerStatus(command);
71 break;
72 case CEC_OPCODE_CEC_VERSION:
73 HandleDeviceCecVersion(command);
74 break;
75 case CEC_OPCODE_SET_MENU_LANGUAGE:
76 HandleSetMenuLanguage(command);
77 break;
78 case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
79 HandleGivePhysicalAddress(command);
80 break;
81 case CEC_OPCODE_GIVE_OSD_NAME:
82 HandleGiveOSDName(command);
83 break;
84 case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
85 HandleGiveDeviceVendorId(command);
86 break;
87 case CEC_OPCODE_DEVICE_VENDOR_ID:
88 bHandlerChanged = HandleDeviceVendorId(command);
89 break;
90 case CEC_OPCODE_VENDOR_COMMAND_WITH_ID:
91 HandleDeviceVendorCommandWithId(command);
92 break;
93 case CEC_OPCODE_GIVE_DECK_STATUS:
94 HandleGiveDeckStatus(command);
95 break;
96 case CEC_OPCODE_DECK_CONTROL:
97 HandleDeckControl(command);
98 break;
99 case CEC_OPCODE_MENU_REQUEST:
100 HandleMenuRequest(command);
101 break;
102 case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
103 HandleGiveDevicePowerStatus(command);
104 break;
105 case CEC_OPCODE_GET_CEC_VERSION:
106 HandleGetCecVersion(command);
107 break;
108 case CEC_OPCODE_USER_CONTROL_PRESSED:
109 HandleUserControlPressed(command);
110 break;
111 case CEC_OPCODE_USER_CONTROL_RELEASE:
112 HandleUserControlRelease(command);
113 break;
114 case CEC_OPCODE_GIVE_AUDIO_STATUS:
115 HandleGiveAudioStatus(command);
116 break;
117 case CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS:
118 HandleGiveSystemAudioModeStatus(command);
119 break;
120 case CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST:
121 HandleSystemAudioModeRequest(command);
122 break;
123 case CEC_OPCODE_REPORT_AUDIO_STATUS:
124 HandleReportAudioStatus(command);
125 break;
126 case CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS:
127 HandleSystemAudioModeStatus(command);
128 break;
129 case CEC_OPCODE_SET_SYSTEM_AUDIO_MODE:
130 HandleSetSystemAudioMode(command);
131 break;
132 case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
133 HandleRequestActiveSource(command);
134 break;
135 case CEC_OPCODE_SET_STREAM_PATH:
136 HandleSetStreamPath(command);
137 break;
138 case CEC_OPCODE_ROUTING_CHANGE:
139 HandleRoutingChange(command);
140 break;
141 case CEC_OPCODE_ROUTING_INFORMATION:
142 HandleRoutingInformation(command);
143 break;
144 case CEC_OPCODE_STANDBY:
145 HandleStandby(command);
146 break;
147 case CEC_OPCODE_ACTIVE_SOURCE:
148 HandleActiveSource(command);
149 break;
150 case CEC_OPCODE_REPORT_PHYSICAL_ADDRESS:
151 HandleReportPhysicalAddress(command);
152 break;
153 case CEC_OPCODE_SET_OSD_NAME:
154 HandleSetOSDName(command);
155 break;
156 case CEC_OPCODE_IMAGE_VIEW_ON:
157 HandleImageViewOn(command);
158 break;
159 case CEC_OPCODE_TEXT_VIEW_ON:
160 HandleTextViewOn(command);
161 break;
162 case CEC_OPCODE_FEATURE_ABORT:
163 HandleFeatureAbort(command);
164 break;
165 default:
166 UnhandledCommand(command);
167 bHandled = false;
168 break;
169 }
170
171 if (bHandled && !bHandlerChanged)
172 {
173 CLockObject lock(&m_receiveMutex);
174 m_condition.Signal();
175 }
176
177 return bHandled;
178 }
179
180 bool CCECCommandHandler::HandleActiveSource(const cec_command &command)
181 {
182 if (command.parameters.size == 2)
183 {
184 uint16_t iAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
185 return m_processor->SetActiveSource(iAddress);
186 }
187
188 return true;
189 }
190
191 bool CCECCommandHandler::HandleDeckControl(const cec_command &command)
192 {
193 CCECBusDevice *device = GetDevice(command.destination);
194 if (device && (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE) && command.parameters.size > 0)
195 {
196 ((CCECPlaybackDevice *) device)->SetDeckControlMode((cec_deck_control_mode) command.parameters[0]);
197 return true;
198 }
199
200 return false;
201 }
202
203 bool CCECCommandHandler::HandleDeviceCecVersion(const cec_command &command)
204 {
205 if (command.parameters.size == 1)
206 {
207 CCECBusDevice *device = GetDevice(command.initiator);
208 if (device)
209 device->SetCecVersion((cec_version) command.parameters[0]);
210 }
211
212 return true;
213 }
214
215 bool CCECCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &command)
216 {
217 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
218 m_processor->TransmitAbort(command.initiator, command.opcode, CEC_ABORT_REASON_REFUSED);
219
220 return true;
221 }
222
223 bool CCECCommandHandler::HandleDeviceVendorId(const cec_command &command)
224 {
225 return SetVendorId(command);
226 }
227
228 bool CCECCommandHandler::HandleFeatureAbort(const cec_command &command)
229 {
230 if (command.parameters.size == 2)
231 {
232 m_processor->m_busDevices[command.initiator]->SetUnsupportedFeature((cec_opcode)command.parameters[0]);
233 }
234 }
235
236 bool CCECCommandHandler::HandleGetCecVersion(const cec_command &command)
237 {
238 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
239 {
240 CCECBusDevice *device = GetDevice(command.destination);
241 if (device)
242 return device->TransmitCECVersion(command.initiator);
243 }
244
245 return false;
246 }
247
248 bool CCECCommandHandler::HandleGiveAudioStatus(const cec_command &command)
249 {
250 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
251 {
252 CCECBusDevice *device = GetDevice(command.destination);
253 if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
254 return ((CCECAudioSystem *) device)->TransmitAudioStatus(command.initiator);
255 }
256
257 return false;
258 }
259
260 bool CCECCommandHandler::HandleGiveDeckStatus(const cec_command &command)
261 {
262 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
263 {
264 CCECBusDevice *device = GetDevice(command.destination);
265 if (device && (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
266 return ((CCECPlaybackDevice *) device)->TransmitDeckStatus(command.initiator);
267 }
268
269 return false;
270 }
271
272 bool CCECCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
273 {
274 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
275 {
276 CCECBusDevice *device = GetDevice(command.destination);
277 if (device)
278 return device->TransmitPowerState(command.initiator);
279 }
280
281 return false;
282 }
283
284 bool CCECCommandHandler::HandleGiveDeviceVendorId(const cec_command &command)
285 {
286 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
287 {
288 CCECBusDevice *device = GetDevice(command.destination);
289 if (device)
290 return device->TransmitVendorID(command.initiator);
291 }
292
293 return false;
294 }
295
296 bool CCECCommandHandler::HandleGiveOSDName(const cec_command &command)
297 {
298 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
299 {
300 CCECBusDevice *device = GetDevice(command.destination);
301 if (device)
302 return device->TransmitOSDName(command.initiator);
303 }
304
305 return false;
306 }
307
308 bool CCECCommandHandler::HandleGivePhysicalAddress(const cec_command &command)
309 {
310 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
311 {
312 CCECBusDevice *device = GetDevice(command.destination);
313 if (device)
314 {
315 device->SetActiveSource();
316 return device->TransmitPhysicalAddress() &&
317 device->TransmitActiveSource();
318 }
319 }
320
321 return false;
322 }
323
324 bool CCECCommandHandler::HandleGiveSystemAudioModeStatus(const cec_command &command)
325 {
326 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
327 {
328 CCECBusDevice *device = GetDevice(command.destination);
329 if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
330 return ((CCECAudioSystem *) device)->TransmitSystemAudioModeStatus(command.initiator);
331 }
332
333 return false;
334 }
335
336 bool CCECCommandHandler::HandleImageViewOn(const cec_command &command)
337 {
338 m_processor->m_busDevices[command.initiator]->SetActiveSource();
339 return true;
340 }
341
342 bool CCECCommandHandler::HandleMenuRequest(const cec_command &command)
343 {
344 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
345 {
346 if (command.parameters[0] == CEC_MENU_REQUEST_TYPE_QUERY)
347 {
348 CCECBusDevice *device = GetDevice(command.destination);
349 if (device)
350 return device->TransmitMenuState(command.initiator);
351 }
352 }
353
354 return false;
355 }
356
357 bool CCECCommandHandler::HandleReportAudioStatus(const cec_command &command)
358 {
359 if (command.parameters.size == 1)
360 {
361 CCECBusDevice *device = GetDevice(command.initiator);
362 if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
363 {
364 ((CCECAudioSystem *)device)->SetAudioStatus(command.parameters[0]);
365 return true;
366 }
367 }
368 return false;
369 }
370
371 bool CCECCommandHandler::HandleReportPhysicalAddress(const cec_command &command)
372 {
373 if (command.parameters.size == 3)
374 {
375 uint16_t iNewAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
376 SetPhysicalAddress(command.initiator, iNewAddress);
377 }
378 return true;
379 }
380
381 bool CCECCommandHandler::HandleReportPowerStatus(const cec_command &command)
382 {
383 if (command.parameters.size == 1)
384 {
385 CCECBusDevice *device = GetDevice(command.initiator);
386 if (device)
387 device->SetPowerStatus((cec_power_status) command.parameters[0]);
388 }
389 return true;
390 }
391
392 bool CCECCommandHandler::HandleRequestActiveSource(const cec_command &command)
393 {
394 if (m_processor->IsStarted())
395 {
396 CStdString strLog;
397 strLog.Format(">> %i requests active source", (uint8_t) command.initiator);
398 m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str());
399
400 vector<CCECBusDevice *> devices;
401 for (int iDevicePtr = (int)GetMyDevices(devices)-1; iDevicePtr >=0; iDevicePtr--)
402 devices[iDevicePtr]->TransmitActiveSource();
403
404 return true;
405 }
406 return false;
407 }
408
409 bool CCECCommandHandler::HandleRoutingChange(const cec_command &command)
410 {
411 if (command.parameters.size == 4)
412 {
413 uint16_t iOldAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
414 uint16_t iNewAddress = ((uint16_t)command.parameters[2] << 8) | ((uint16_t)command.parameters[3]);
415
416 CCECBusDevice *device = GetDevice(command.initiator);
417 if (device)
418 device->SetStreamPath(iNewAddress, iOldAddress);
419 }
420 return true;
421 }
422
423 bool CCECCommandHandler::HandleRoutingInformation(const cec_command &command)
424 {
425 if (command.parameters.size == 2)
426 {
427 uint16_t iNewAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
428 m_processor->SetActiveSource(iNewAddress);
429 }
430
431 return false;
432 }
433
434 bool CCECCommandHandler::HandleSetMenuLanguage(const cec_command &command)
435 {
436 if (command.parameters.size == 3)
437 {
438 CCECBusDevice *device = GetDevice(command.initiator);
439 if (device)
440 {
441 cec_menu_language language;
442 language.device = command.initiator;
443 for (uint8_t iPtr = 0; iPtr < 4; iPtr++)
444 language.language[iPtr] = command.parameters[iPtr];
445 language.language[3] = 0;
446 device->SetMenuLanguage(language);
447 return true;
448 }
449 }
450 return false;
451 }
452
453 bool CCECCommandHandler::HandleSetOSDName(const cec_command &command)
454 {
455 if (command.parameters.size > 0)
456 {
457 CCECBusDevice *device = GetDevice(command.initiator);
458 if (device)
459 {
460 char buf[1024];
461 for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++)
462 buf[iPtr] = (char)command.parameters[iPtr];
463 buf[command.parameters.size] = 0;
464
465 CStdString strName(buf);
466 device->SetOSDName(strName);
467
468 return true;
469 }
470 }
471 return false;
472 }
473
474 bool CCECCommandHandler::HandleSetStreamPath(const cec_command &command)
475 {
476 if (m_processor->IsStarted() && command.parameters.size >= 2)
477 {
478 uint16_t iStreamAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
479 CStdString strLog;
480 strLog.Format(">> %i sets stream path to physical address %04x", command.initiator, iStreamAddress);
481 m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str());
482
483 /* one of the device handled by libCEC has been made active */
484 CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamAddress);
485 if (device && m_busDevice->MyLogicalAddressContains(device->GetLogicalAddress()))
486 {
487 device->SetActiveSource();
488 device->TransmitActiveSource();
489 }
490 }
491 return false;
492 }
493
494 bool CCECCommandHandler::HandleSystemAudioModeRequest(const cec_command &command)
495 {
496 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
497 {
498 CCECBusDevice *device = GetDevice(command.destination);
499 if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
500 {
501 if (command.parameters.size >= 2)
502 {
503 device->SetPowerStatus(CEC_POWER_STATUS_ON);
504 ((CCECAudioSystem *) device)->SetSystemAudioModeStatus(CEC_SYSTEM_AUDIO_STATUS_ON);
505 uint16_t iNewAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
506 CCECBusDevice *newActiveDevice = GetDeviceByPhysicalAddress(iNewAddress);
507 if (newActiveDevice)
508 newActiveDevice->SetActiveSource();
509 return ((CCECAudioSystem *) device)->TransmitSetSystemAudioMode(command.initiator);
510 }
511 else
512 {
513 ((CCECAudioSystem *) device)->SetSystemAudioModeStatus(CEC_SYSTEM_AUDIO_STATUS_OFF);
514 return ((CCECAudioSystem *) device)->TransmitSetSystemAudioMode(command.initiator);
515 }
516 }
517 }
518 return false;
519 }
520
521 bool CCECCommandHandler::HandleStandby(const cec_command &command)
522 {
523 CCECBusDevice *device = GetDevice(command.initiator);
524 if (device)
525 device->SetPowerStatus(CEC_POWER_STATUS_STANDBY);
526
527 return true;
528 }
529
530 bool CCECCommandHandler::HandleSystemAudioModeStatus(const cec_command &command)
531 {
532 if (command.parameters.size == 1)
533 {
534 CCECBusDevice *device = GetDevice(command.initiator);
535 if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
536 {
537 ((CCECAudioSystem *)device)->SetSystemAudioModeStatus((cec_system_audio_status)command.parameters[0]);
538 return true;
539 }
540 }
541
542 return false;
543 }
544
545 bool CCECCommandHandler::HandleSetSystemAudioMode(const cec_command &command)
546 {
547 if (command.parameters.size == 1)
548 {
549 CCECBusDevice *device = GetDevice(command.initiator);
550 if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
551 {
552 ((CCECAudioSystem *)device)->SetSystemAudioModeStatus((cec_system_audio_status)command.parameters[0]);
553 return true;
554 }
555 }
556
557 return false;
558 }
559
560 bool CCECCommandHandler::HandleTextViewOn(const cec_command &command)
561 {
562 m_processor->m_busDevices[command.initiator]->SetActiveSource();
563 return true;
564 }
565
566 bool CCECCommandHandler::HandleUserControlPressed(const cec_command &command)
567 {
568 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination) && command.parameters.size > 0)
569 {
570 m_processor->AddKey();
571
572 if (command.parameters[0] <= CEC_USER_CONTROL_CODE_MAX)
573 {
574 CStdString strLog;
575 strLog.Format("key pressed: %x", command.parameters[0]);
576 m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str());
577
578 if (command.parameters[0] == CEC_USER_CONTROL_CODE_POWER ||
579 command.parameters[0] == CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION)
580 {
581 CCECBusDevice *device = GetDevice(command.destination);
582 if (device)
583 {
584 device->SetPowerStatus(CEC_POWER_STATUS_ON);
585 if (device->MyLogicalAddressContains(device->GetLogicalAddress()))
586 {
587 device->SetActiveSource();
588 device->TransmitActiveSource();
589
590 if (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
591 device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
592 ((CCECPlaybackDevice *)device)->TransmitDeckStatus(command.initiator);
593 }
594 }
595 }
596 else
597 {
598 m_processor->SetCurrentButton((cec_user_control_code) command.parameters[0]);
599 }
600 return true;
601 }
602 }
603 return false;
604 }
605
606 bool CCECCommandHandler::HandleUserControlRelease(const cec_command &command)
607 {
608 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
609 m_processor->AddKey();
610
611 return true;
612 }
613
614 void CCECCommandHandler::UnhandledCommand(const cec_command &command)
615 {
616 CStdString strLog;
617 strLog.Format("unhandled command with opcode %02x from address %d", command.opcode, command.initiator);
618 m_busDevice->AddLog(CEC_LOG_DEBUG, strLog);
619 }
620
621 unsigned int CCECCommandHandler::GetMyDevices(vector<CCECBusDevice *> &devices) const
622 {
623 unsigned int iReturn(0);
624
625 cec_logical_addresses addresses = m_processor->GetLogicalAddresses();
626 for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
627 {
628 if (addresses[iPtr])
629 {
630 devices.push_back(GetDevice((cec_logical_address) iPtr));
631 ++iReturn;
632 }
633 }
634
635 return iReturn;
636 }
637
638 CCECBusDevice *CCECCommandHandler::GetDevice(cec_logical_address iLogicalAddress) const
639 {
640 CCECBusDevice *device = NULL;
641
642 if (iLogicalAddress >= CECDEVICE_TV && iLogicalAddress <= CECDEVICE_BROADCAST)
643 device = m_processor->m_busDevices[iLogicalAddress];
644
645 return device;
646 }
647
648 CCECBusDevice *CCECCommandHandler::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress) const
649 {
650 return m_processor->GetDeviceByPhysicalAddress(iPhysicalAddress);
651 }
652
653 CCECBusDevice *CCECCommandHandler::GetDeviceByType(cec_device_type type) const
654 {
655 return m_processor->GetDeviceByType(type);
656 }
657
658 bool CCECCommandHandler::SetVendorId(const cec_command &command)
659 {
660 bool bChanged(false);
661 if (command.parameters.size < 3)
662 {
663 m_busDevice->AddLog(CEC_LOG_WARNING, "invalid vendor ID received");
664 return bChanged;
665 }
666
667 uint64_t iVendorId = ((uint64_t)command.parameters[0] << 16) +
668 ((uint64_t)command.parameters[1] << 8) +
669 (uint64_t)command.parameters[2];
670
671 CCECBusDevice *device = GetDevice((cec_logical_address) command.initiator);
672 if (device)
673 bChanged = device->SetVendorId(iVendorId);
674 return bChanged;
675 }
676
677 void CCECCommandHandler::SetPhysicalAddress(cec_logical_address iAddress, uint16_t iNewAddress)
678 {
679 if (!m_busDevice->MyLogicalAddressContains(iAddress))
680 {
681 bool bOurAddress(m_processor->GetPhysicalAddress() == iNewAddress);
682 GetDevice(iAddress)->SetPhysicalAddress(iNewAddress);
683 if (bOurAddress)
684 {
685 /* another device reported the same physical address as ours
686 * since we don't have physical address detection yet, we'll just use the
687 * given address, increased by 0x100 for now */
688 m_processor->SetPhysicalAddress(iNewAddress + 0x100);
689 }
690 }
691 }
692
693 void CCECCommandHandler::HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination)
694 {
695 CStdString strLog;
696 strLog.Format("<< POLL: %s (%x) -> %s (%x)", m_processor->ToString(iInitiator), iInitiator, m_processor->ToString(iDestination), iDestination);
697 m_processor->AddLog(CEC_LOG_DEBUG, strLog);
698 }
699
700 bool CCECCommandHandler::HandleReceiveFailed(void)
701 {
702 /* default = error */
703 return true;
704 }
705
706 bool CCECCommandHandler::TransmitPowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination)
707 {
708 cec_command command;
709 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_IMAGE_VIEW_ON);
710
711 return Transmit(command);
712 }
713
714 bool CCECCommandHandler::TransmitStandby(const cec_logical_address iInitiator, const cec_logical_address iDestination)
715 {
716 cec_command command;
717 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_STANDBY);
718
719 return Transmit(command);
720 }
721
722 bool CCECCommandHandler::TransmitRequestCecVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination)
723 {
724 cec_command command;
725 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GET_CEC_VERSION);
726
727 return Transmit(command);
728 }
729
730 bool CCECCommandHandler::TransmitRequestMenuLanguage(const cec_logical_address iInitiator, const cec_logical_address iDestination)
731 {
732 cec_command command;
733 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GET_MENU_LANGUAGE);
734
735 return Transmit(command);
736 }
737
738 bool CCECCommandHandler::TransmitRequestOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination)
739 {
740 cec_command command;
741 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_OSD_NAME);
742
743 return Transmit(command);
744 }
745
746 bool CCECCommandHandler::TransmitRequestPhysicalAddress(const cec_logical_address iInitiator, const cec_logical_address iDestination)
747 {
748 cec_command command;
749 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_PHYSICAL_ADDRESS);
750
751 return Transmit(command);
752 }
753
754 bool CCECCommandHandler::TransmitRequestPowerStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination)
755 {
756 cec_command command;
757 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_POWER_STATUS);
758
759 return Transmit(command);
760 }
761
762 bool CCECCommandHandler::TransmitRequestVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination)
763 {
764 cec_command command;
765 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
766
767 return Transmit(command);
768 }
769
770 bool CCECCommandHandler::TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress)
771 {
772 cec_command command;
773 cec_command::Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_ACTIVE_SOURCE);
774 command.parameters.PushBack((uint8_t) ((iPhysicalAddress >> 8) & 0xFF));
775 command.parameters.PushBack((uint8_t) (iPhysicalAddress & 0xFF));
776
777 return Transmit(command);
778 }
779
780 bool CCECCommandHandler::TransmitCECVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_version cecVersion)
781 {
782 cec_command command;
783 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_CEC_VERSION);
784 command.parameters.PushBack((uint8_t)cecVersion);
785
786 return Transmit(command);
787 }
788
789 bool CCECCommandHandler::TransmitInactiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress)
790 {
791 cec_command command;
792 cec_command::Format(command, iInitiator, CECDEVICE_TV, CEC_OPCODE_INACTIVE_SOURCE);
793 command.parameters.PushBack((iPhysicalAddress >> 8) & 0xFF);
794 command.parameters.PushBack(iPhysicalAddress & 0xFF);
795
796 return Transmit(command);
797 }
798
799 bool CCECCommandHandler::TransmitMenuState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_menu_state menuState)
800 {
801 cec_command command;
802 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_MENU_STATUS);
803 command.parameters.PushBack((uint8_t)menuState);
804
805 return Transmit(command);
806 }
807
808 bool CCECCommandHandler::TransmitOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, CStdString strDeviceName)
809 {
810 cec_command command;
811 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SET_OSD_NAME);
812 for (unsigned int iPtr = 0; iPtr < strDeviceName.length(); iPtr++)
813 command.parameters.PushBack(strDeviceName.at(iPtr));
814
815 return Transmit(command);
816 }
817
818 bool CCECCommandHandler::TransmitOSDString(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_display_control duration, const char *strMessage)
819 {
820 cec_command command;
821 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SET_OSD_STRING);
822 command.parameters.PushBack((uint8_t)duration);
823
824 unsigned int iLen = strlen(strMessage);
825 if (iLen > 13) iLen = 13;
826
827 for (unsigned int iPtr = 0; iPtr < iLen; iPtr++)
828 command.parameters.PushBack(strMessage[iPtr]);
829
830 return Transmit(command);
831 }
832
833 bool CCECCommandHandler::TransmitPhysicalAddress(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, cec_device_type type)
834 {
835 cec_command command;
836 cec_command::Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_REPORT_PHYSICAL_ADDRESS);
837 command.parameters.PushBack((uint8_t) ((iPhysicalAddress >> 8) & 0xFF));
838 command.parameters.PushBack((uint8_t) (iPhysicalAddress & 0xFF));
839 command.parameters.PushBack((uint8_t) (type));
840
841 return Transmit(command);
842 }
843
844 bool CCECCommandHandler::TransmitPoll(const cec_logical_address iInitiator, const cec_logical_address iDestination)
845 {
846 cec_command command;
847 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_NONE);
848
849 return Transmit(command, false);
850 }
851
852 bool CCECCommandHandler::TransmitPowerState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_power_status state)
853 {
854 cec_command command;
855 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_REPORT_POWER_STATUS);
856 command.parameters.PushBack((uint8_t) state);
857
858 return Transmit(command);
859 }
860
861 bool CCECCommandHandler::TransmitVendorID(const cec_logical_address iInitiator, uint64_t iVendorId)
862 {
863 cec_command command;
864 cec_command::Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_DEVICE_VENDOR_ID);
865
866 command.parameters.PushBack((uint8_t) (((uint64_t)iVendorId >> 16) & 0xFF));
867 command.parameters.PushBack((uint8_t) (((uint64_t)iVendorId >> 8) & 0xFF));
868 command.parameters.PushBack((uint8_t) ((uint64_t)iVendorId & 0xFF));
869
870 return Transmit(command);
871 }
872
873 bool CCECCommandHandler::TransmitAudioStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint8_t state)
874 {
875 cec_command command;
876 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_REPORT_AUDIO_STATUS);
877 command.parameters.PushBack(state);
878
879 return Transmit(command);
880 }
881
882 bool CCECCommandHandler::TransmitSetSystemAudioMode(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state)
883 {
884 cec_command command;
885 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SET_SYSTEM_AUDIO_MODE);
886 command.parameters.PushBack((uint8_t)state);
887
888 return Transmit(command);
889 }
890
891 bool CCECCommandHandler::TransmitSystemAudioModeStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state)
892 {
893 cec_command command;
894 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS);
895 command.parameters.PushBack((uint8_t)state);
896
897 return Transmit(command);
898 }
899
900 bool CCECCommandHandler::TransmitDeckStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_deck_info state)
901 {
902 cec_command command;
903 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_DECK_STATUS);
904 command.PushBack((uint8_t)state);
905
906 return Transmit(command);
907 }
908
909 bool CCECCommandHandler::TransmitKeypress(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */)
910 {
911 cec_command command;
912 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_USER_CONTROL_PRESSED);
913 command.parameters.PushBack((uint8_t)key);
914
915 return Transmit(command, bWait);
916 }
917
918 bool CCECCommandHandler::TransmitKeyRelease(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWait /* = true */)
919 {
920 cec_command command;
921 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_USER_CONTROL_RELEASE);
922
923 return Transmit(command, bWait);
924 }
925
926 bool CCECCommandHandler::Transmit(cec_command &command, bool bExpectResponse /* = true */)
927 {
928 command.transmit_timeout = m_iTransmitTimeout;
929
930 CLockObject writeLock(&m_processor->m_transmitMutex);
931 CLockObject receiveLock(&m_receiveMutex);
932 if (m_processor->Transmit(command))
933 {
934 if (bExpectResponse)
935 return m_condition.Wait(&m_receiveMutex, m_iTransmitWait);
936 return true;
937 }
938
939 return false;
940 }
941
942 bool CCECCommandHandler::InitHandler(void)
943 {
944 if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV)
945 {
946 CCECBusDevice *primary = m_processor->GetPrimaryDevice();
947 primary->SetPowerStatus(CEC_POWER_STATUS_ON);
948 primary->SetMenuState(CEC_MENU_STATE_ACTIVATED);
949
950 if (m_processor->GetPrimaryDevice()->GetPhysicalAddress(false) != 0xffff)
951 {
952 m_processor->SetActiveSource();
953 primary->TransmitMenuState(m_busDevice->GetLogicalAddress());
954 m_bHandlerInited = true;
955 }
956 }
957 return true;
958 }