cec: fix handler init
[deb_libcec.git] / src / lib / implementations / CECCommandHandler.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 "CECCommandHandler.h"
eafa9d46 34#include "../devices/CECBusDevice.h"
a1f8fb1b 35#include "../devices/CECAudioSystem.h"
28089abc 36#include "../devices/CECPlaybackDevice.h"
387b6f6f 37#include "../CECProcessor.h"
e9de9629
LOK
38
39using namespace CEC;
8747dd4f 40using namespace std;
e9de9629 41
8fa35473
LOK
42CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice) :
43 m_busDevice(busDevice),
44 m_processor(m_busDevice->GetProcessor()),
ae693aaa
LOK
45 m_iTransmitTimeout(CEC_DEFAULT_TRANSMIT_TIMEOUT),
46 m_iTransmitWait(CEC_DEFAULT_TRANSMIT_WAIT),
89a726fa
LOK
47 m_iTransmitRetries(CEC_DEFAULT_TRANSMIT_RETRIES),
48 m_bHandlerInited(false)
e9de9629 49{
8fa35473
LOK
50}
51
52CCECCommandHandler::~CCECCommandHandler(void)
53{
54 m_condition.Broadcast();
e9de9629
LOK
55}
56
57bool CCECCommandHandler::HandleCommand(const cec_command &command)
58{
8fa35473 59 bool bHandled(true), bHandlerChanged(false);
e9de9629 60
5e822b09 61 CStdString strLog;
fcf10e27 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);
5e822b09
LOK
63 m_busDevice->AddLog(CEC_LOG_NOTICE, strLog);
64
855a3a98
LOK
65 m_processor->AddCommand(command);
66
6b72afcd 67 switch(command.opcode)
e9de9629 68 {
6b72afcd
LOK
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:
8fa35473 88 bHandlerChanged = HandleDeviceVendorId(command);
6b72afcd
LOK
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:
aa517a0d
LOK
121 HandleSystemAudioModeRequest(command);
122 break;
123 case CEC_OPCODE_REPORT_AUDIO_STATUS:
855a3a98 124 HandleReportAudioStatus(command);
aa517a0d
LOK
125 break;
126 case CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS:
855a3a98 127 HandleSystemAudioModeStatus(command);
aa517a0d
LOK
128 break;
129 case CEC_OPCODE_SET_SYSTEM_AUDIO_MODE:
855a3a98 130 HandleSetSystemAudioMode(command);
6b72afcd
LOK
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;
907bd60f
LOK
141 case CEC_OPCODE_ROUTING_INFORMATION:
142 HandleRoutingInformation(command);
143 break;
6b72afcd
LOK
144 case CEC_OPCODE_STANDBY:
145 HandleStandby(command);
146 break;
147 case CEC_OPCODE_ACTIVE_SOURCE:
148 HandleActiveSource(command);
149 break;
907bd60f
LOK
150 case CEC_OPCODE_REPORT_PHYSICAL_ADDRESS:
151 HandleReportPhysicalAddress(command);
152 break;
15d1a84c
LOK
153 case CEC_OPCODE_SET_OSD_NAME:
154 HandleSetOSDName(command);
155 break;
1a6669b8
LOK
156 case CEC_OPCODE_IMAGE_VIEW_ON:
157 HandleImageViewOn(command);
158 break;
159 case CEC_OPCODE_TEXT_VIEW_ON:
160 HandleTextViewOn(command);
161 break;
4d738fe3
LOK
162 case CEC_OPCODE_FEATURE_ABORT:
163 HandleFeatureAbort(command);
164 break;
6b72afcd
LOK
165 default:
166 UnhandledCommand(command);
e9de9629 167 bHandled = false;
6b72afcd 168 break;
e9de9629
LOK
169 }
170
8fa35473
LOK
171 if (bHandled && !bHandlerChanged)
172 {
6359ffd1 173 CLockObject lock(&m_receiveMutex);
8fa35473
LOK
174 m_condition.Signal();
175 }
176
e9de9629
LOK
177 return bHandled;
178}
179
be5b0e24
LOK
180bool 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]);
37b0c572 185 return m_processor->SetActiveSource(iAddress);
be5b0e24
LOK
186 }
187
188 return true;
189}
190
a9232a79
LOK
191bool CCECCommandHandler::HandleDeckControl(const cec_command &command)
192{
193 CCECBusDevice *device = GetDevice(command.destination);
88e5de6f 194 if (device && (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE) && command.parameters.size > 0)
a9232a79
LOK
195 {
196 ((CCECPlaybackDevice *) device)->SetDeckControlMode((cec_deck_control_mode) command.parameters[0]);
197 return true;
198 }
199
200 return false;
201}
202
6a1c0009
LOK
203bool 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
e9de9629
LOK
215bool CCECCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &command)
216{
5f316715 217 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
fcf10e27 218 m_processor->TransmitAbort(command.initiator, command.opcode, CEC_ABORT_REASON_REFUSED);
6b72afcd 219
6a1c0009 220 return true;
e9de9629
LOK
221}
222
223bool CCECCommandHandler::HandleDeviceVendorId(const cec_command &command)
224{
8fa35473 225 return SetVendorId(command);
e9de9629
LOK
226}
227
4d738fe3
LOK
228bool 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
e9de9629
LOK
236bool CCECCommandHandler::HandleGetCecVersion(const cec_command &command)
237{
5f316715 238 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
6b72afcd
LOK
239 {
240 CCECBusDevice *device = GetDevice(command.destination);
241 if (device)
242 return device->TransmitCECVersion(command.initiator);
243 }
0f23c85c
LOK
244
245 return false;
e9de9629
LOK
246}
247
a1f8fb1b
LOK
248bool CCECCommandHandler::HandleGiveAudioStatus(const cec_command &command)
249{
5f316715 250 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
6b72afcd
LOK
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 }
a1f8fb1b
LOK
256
257 return false;
258}
259
e9de9629
LOK
260bool CCECCommandHandler::HandleGiveDeckStatus(const cec_command &command)
261{
5f316715 262 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
6b72afcd
LOK
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 }
0f23c85c
LOK
268
269 return false;
e9de9629
LOK
270}
271
272bool CCECCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
273{
5f316715 274 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
6b72afcd
LOK
275 {
276 CCECBusDevice *device = GetDevice(command.destination);
277 if (device)
278 return device->TransmitPowerState(command.initiator);
279 }
0f23c85c
LOK
280
281 return false;
e9de9629
LOK
282}
283
284bool CCECCommandHandler::HandleGiveDeviceVendorId(const cec_command &command)
285{
5f316715 286 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
6b72afcd
LOK
287 {
288 CCECBusDevice *device = GetDevice(command.destination);
289 if (device)
290 return device->TransmitVendorID(command.initiator);
291 }
0f23c85c
LOK
292
293 return false;
e9de9629
LOK
294}
295
296bool CCECCommandHandler::HandleGiveOSDName(const cec_command &command)
297{
5f316715 298 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
6b72afcd
LOK
299 {
300 CCECBusDevice *device = GetDevice(command.destination);
301 if (device)
302 return device->TransmitOSDName(command.initiator);
303 }
0f23c85c
LOK
304
305 return false;
e9de9629
LOK
306}
307
308bool CCECCommandHandler::HandleGivePhysicalAddress(const cec_command &command)
309{
5f316715 310 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
6b72afcd
LOK
311 {
312 CCECBusDevice *device = GetDevice(command.destination);
313 if (device)
3c20db73
LOK
314 {
315 device->SetActiveSource();
316 return device->TransmitPhysicalAddress() &&
317 device->TransmitActiveSource();
318 }
6b72afcd 319 }
09c10b66
LOK
320
321 return false;
e9de9629
LOK
322}
323
1a6669b8
LOK
324bool CCECCommandHandler::HandleGiveSystemAudioModeStatus(const cec_command &command)
325{
5f316715 326 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
1a6669b8
LOK
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
336bool CCECCommandHandler::HandleImageViewOn(const cec_command &command)
337{
37b0c572 338 m_processor->m_busDevices[command.initiator]->SetActiveSource();
1a6669b8
LOK
339 return true;
340}
341
e9de9629
LOK
342bool CCECCommandHandler::HandleMenuRequest(const cec_command &command)
343{
5f316715 344 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
0f23c85c 345 {
6b72afcd
LOK
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 }
15d1a84c
LOK
352 }
353
354 return false;
355}
356
357bool 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)
6b72afcd 363 {
15d1a84c
LOK
364 ((CCECAudioSystem *)device)->SetAudioStatus(command.parameters[0]);
365 return true;
6b72afcd 366 }
0f23c85c
LOK
367 }
368 return false;
e9de9629
LOK
369}
370
907bd60f
LOK
371bool CCECCommandHandler::HandleReportPhysicalAddress(const cec_command &command)
372{
0bfce006 373 if (command.parameters.size == 3)
907bd60f
LOK
374 {
375 uint16_t iNewAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
16b1e052 376 SetPhysicalAddress(command.initiator, iNewAddress);
907bd60f
LOK
377 }
378 return true;
379}
380
e55f3f70
LOK
381bool 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
e9de9629
LOK
392bool CCECCommandHandler::HandleRequestActiveSource(const cec_command &command)
393{
5f316715
LOK
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());
8747dd4f 399
5f316715
LOK
400 vector<CCECBusDevice *> devices;
401 for (int iDevicePtr = (int)GetMyDevices(devices)-1; iDevicePtr >=0; iDevicePtr--)
402 devices[iDevicePtr]->TransmitActiveSource();
c4098482 403
5f316715
LOK
404 return true;
405 }
406 return false;
e9de9629
LOK
407}
408
409bool 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]);
e9de9629 415
0f23c85c
LOK
416 CCECBusDevice *device = GetDevice(command.initiator);
417 if (device)
9dc04b07 418 device->SetStreamPath(iNewAddress, iOldAddress);
e9de9629
LOK
419 }
420 return true;
421}
422
907bd60f
LOK
423bool 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]);
37b0c572 428 m_processor->SetActiveSource(iNewAddress);
907bd60f 429 }
15d1a84c
LOK
430
431 return false;
907bd60f
LOK
432}
433
a3269a0a
LOK
434bool 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;
56701628 443 for (uint8_t iPtr = 0; iPtr < 4; iPtr++)
a3269a0a
LOK
444 language.language[iPtr] = command.parameters[iPtr];
445 language.language[3] = 0;
446 device->SetMenuLanguage(language);
15d1a84c
LOK
447 return true;
448 }
449 }
450 return false;
451}
452
453bool 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);
6b72afcd 467
15d1a84c 468 return true;
a3269a0a
LOK
469 }
470 }
15d1a84c 471 return false;
a3269a0a
LOK
472}
473
e9de9629
LOK
474bool CCECCommandHandler::HandleSetStreamPath(const cec_command &command)
475{
5f316715 476 if (m_processor->IsStarted() && command.parameters.size >= 2)
e9de9629 477 {
b6c7bc94 478 uint16_t iStreamAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
e9de9629 479 CStdString strLog;
b6c7bc94 480 strLog.Format(">> %i sets stream path to physical address %04x", command.initiator, iStreamAddress);
e9de9629 481 m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str());
72689600
LOK
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 }
e9de9629 490 }
15d1a84c 491 return false;
e9de9629
LOK
492}
493
aa517a0d 494bool CCECCommandHandler::HandleSystemAudioModeRequest(const cec_command &command)
e5e86c76 495{
5f316715 496 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
e5e86c76
LOK
497 {
498 CCECBusDevice *device = GetDevice(command.destination);
aa517a0d
LOK
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)
37b0c572 508 newActiveDevice->SetActiveSource();
aa517a0d
LOK
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 }
e5e86c76 517 }
6b72afcd 518 return false;
e5e86c76
LOK
519}
520
4d6b4433
LOK
521bool CCECCommandHandler::HandleStandby(const cec_command &command)
522{
523 CCECBusDevice *device = GetDevice(command.initiator);
524 if (device)
525 device->SetPowerStatus(CEC_POWER_STATUS_STANDBY);
6b72afcd 526
4d6b4433
LOK
527 return true;
528}
529
aa517a0d 530bool CCECCommandHandler::HandleSystemAudioModeStatus(const cec_command &command)
868dc71f 531{
aa517a0d 532 if (command.parameters.size == 1)
868dc71f 533 {
aa517a0d
LOK
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
545bool 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 }
868dc71f
LOK
555 }
556
557 return false;
558}
559
1a6669b8 560bool CCECCommandHandler::HandleTextViewOn(const cec_command &command)
cf0ecd85 561{
37b0c572 562 m_processor->m_busDevices[command.initiator]->SetActiveSource();
1a6669b8 563 return true;
cf0ecd85
LOK
564}
565
e9de9629
LOK
566bool CCECCommandHandler::HandleUserControlPressed(const cec_command &command)
567{
5f316715 568 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination) && command.parameters.size > 0)
e9de9629 569 {
fcf10e27 570 m_processor->AddKey();
e9de9629
LOK
571
572 if (command.parameters[0] <= CEC_USER_CONTROL_CODE_MAX)
573 {
574 CStdString strLog;
68391d4f 575 strLog.Format("key pressed: %x", command.parameters[0]);
e9de9629
LOK
576 m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str());
577
68391d4f
LOK
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)
3fd2a2b8 583 {
68391d4f 584 device->SetPowerStatus(CEC_POWER_STATUS_ON);
3fd2a2b8
LOK
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 }
68391d4f 595 }
d1ab114f
LOK
596 else
597 {
598 m_processor->SetCurrentButton((cec_user_control_code) command.parameters[0]);
599 }
15d1a84c 600 return true;
e9de9629
LOK
601 }
602 }
15d1a84c 603 return false;
e9de9629
LOK
604}
605
606bool CCECCommandHandler::HandleUserControlRelease(const cec_command &command)
607{
5f316715 608 if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
fcf10e27 609 m_processor->AddKey();
6b72afcd 610
e9de9629
LOK
611 return true;
612}
613
614void CCECCommandHandler::UnhandledCommand(const cec_command &command)
615{
b5b53c7d
LOK
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);
0f23c85c
LOK
619}
620
8747dd4f
LOK
621unsigned int CCECCommandHandler::GetMyDevices(vector<CCECBusDevice *> &devices) const
622{
623 unsigned int iReturn(0);
624
fcf10e27 625 cec_logical_addresses addresses = m_processor->GetLogicalAddresses();
f2198ab5 626 for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
8747dd4f
LOK
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
0f23c85c
LOK
638CCECBusDevice *CCECCommandHandler::GetDevice(cec_logical_address iLogicalAddress) const
639{
640 CCECBusDevice *device = NULL;
641
642 if (iLogicalAddress >= CECDEVICE_TV && iLogicalAddress <= CECDEVICE_BROADCAST)
fcf10e27 643 device = m_processor->m_busDevices[iLogicalAddress];
0f23c85c
LOK
644
645 return device;
e9de9629 646}
6685ae07
LOK
647
648CCECBusDevice *CCECCommandHandler::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress) const
649{
fcf10e27 650 return m_processor->GetDeviceByPhysicalAddress(iPhysicalAddress);
6685ae07 651}
181b3475 652
c4098482
LOK
653CCECBusDevice *CCECCommandHandler::GetDeviceByType(cec_device_type type) const
654{
fcf10e27 655 return m_processor->GetDeviceByType(type);
c4098482
LOK
656}
657
8fa35473 658bool CCECCommandHandler::SetVendorId(const cec_command &command)
181b3475 659{
8fa35473 660 bool bChanged(false);
181b3475
LOK
661 if (command.parameters.size < 3)
662 {
663 m_busDevice->AddLog(CEC_LOG_WARNING, "invalid vendor ID received");
8fa35473 664 return bChanged;
181b3475
LOK
665 }
666
bae71306
LOK
667 uint64_t iVendorId = ((uint64_t)command.parameters[0] << 16) +
668 ((uint64_t)command.parameters[1] << 8) +
181b3475
LOK
669 (uint64_t)command.parameters[2];
670
671 CCECBusDevice *device = GetDevice((cec_logical_address) command.initiator);
672 if (device)
8fa35473
LOK
673 bChanged = device->SetVendorId(iVendorId);
674 return bChanged;
181b3475 675}
5e822b09 676
16b1e052
LOK
677void CCECCommandHandler::SetPhysicalAddress(cec_logical_address iAddress, uint16_t iNewAddress)
678{
679 if (!m_busDevice->MyLogicalAddressContains(iAddress))
680 {
fcf10e27 681 bool bOurAddress(m_processor->GetPhysicalAddress() == iNewAddress);
16b1e052
LOK
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 */
fcf10e27 688 m_processor->SetPhysicalAddress(iNewAddress + 0x100);
16b1e052
LOK
689 }
690 }
691}
855a3a98
LOK
692
693void 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
700bool CCECCommandHandler::HandleReceiveFailed(void)
701{
702 /* default = error */
703 return true;
704}
8fa35473
LOK
705
706bool CCECCommandHandler::TransmitPowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination)
707{
708 cec_command command;
ae693aaa 709 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_IMAGE_VIEW_ON);
8fa35473
LOK
710
711 return Transmit(command);
712}
713
714bool CCECCommandHandler::TransmitStandby(const cec_logical_address iInitiator, const cec_logical_address iDestination)
715{
716 cec_command command;
ae693aaa 717 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_STANDBY);
8fa35473
LOK
718
719 return Transmit(command);
720}
721
722bool CCECCommandHandler::TransmitRequestCecVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination)
723{
724 cec_command command;
ae693aaa 725 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GET_CEC_VERSION);
8fa35473
LOK
726
727 return Transmit(command);
728}
729
730bool CCECCommandHandler::TransmitRequestMenuLanguage(const cec_logical_address iInitiator, const cec_logical_address iDestination)
731{
732 cec_command command;
ae693aaa 733 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GET_MENU_LANGUAGE);
8fa35473
LOK
734
735 return Transmit(command);
736}
737
738bool CCECCommandHandler::TransmitRequestOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination)
739{
740 cec_command command;
ae693aaa 741 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_OSD_NAME);
8fa35473
LOK
742
743 return Transmit(command);
744}
745
746bool CCECCommandHandler::TransmitRequestPhysicalAddress(const cec_logical_address iInitiator, const cec_logical_address iDestination)
747{
748 cec_command command;
ae693aaa 749 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_PHYSICAL_ADDRESS);
8fa35473
LOK
750
751 return Transmit(command);
752}
753
754bool CCECCommandHandler::TransmitRequestPowerStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination)
755{
756 cec_command command;
ae693aaa 757 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_POWER_STATUS);
8fa35473
LOK
758
759 return Transmit(command);
760}
761
762bool CCECCommandHandler::TransmitRequestVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination)
763{
764 cec_command command;
ae693aaa 765 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
8fa35473
LOK
766
767 return Transmit(command);
768}
769
770bool CCECCommandHandler::TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress)
771{
772 cec_command command;
ae693aaa 773 cec_command::Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_ACTIVE_SOURCE);
8fa35473
LOK
774 command.parameters.PushBack((uint8_t) ((iPhysicalAddress >> 8) & 0xFF));
775 command.parameters.PushBack((uint8_t) (iPhysicalAddress & 0xFF));
776
777 return Transmit(command);
778}
779
780bool CCECCommandHandler::TransmitCECVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_version cecVersion)
781{
782 cec_command command;
ae693aaa 783 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_CEC_VERSION);
8fa35473
LOK
784 command.parameters.PushBack((uint8_t)cecVersion);
785
786 return Transmit(command);
787}
788
789bool CCECCommandHandler::TransmitInactiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress)
790{
791 cec_command command;
ae693aaa 792 cec_command::Format(command, iInitiator, CECDEVICE_TV, CEC_OPCODE_INACTIVE_SOURCE);
8fa35473
LOK
793 command.parameters.PushBack((iPhysicalAddress >> 8) & 0xFF);
794 command.parameters.PushBack(iPhysicalAddress & 0xFF);
795
796 return Transmit(command);
797}
798
799bool CCECCommandHandler::TransmitMenuState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_menu_state menuState)
800{
801 cec_command command;
ae693aaa 802 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_MENU_STATUS);
8fa35473
LOK
803 command.parameters.PushBack((uint8_t)menuState);
804
805 return Transmit(command);
806}
807
808bool CCECCommandHandler::TransmitOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, CStdString strDeviceName)
809{
810 cec_command command;
ae693aaa 811 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SET_OSD_NAME);
8fa35473
LOK
812 for (unsigned int iPtr = 0; iPtr < strDeviceName.length(); iPtr++)
813 command.parameters.PushBack(strDeviceName.at(iPtr));
814
815 return Transmit(command);
816}
817
818bool CCECCommandHandler::TransmitOSDString(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_display_control duration, const char *strMessage)
819{
820 cec_command command;
ae693aaa 821 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SET_OSD_STRING);
8fa35473
LOK
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
833bool CCECCommandHandler::TransmitPhysicalAddress(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, cec_device_type type)
834{
835 cec_command command;
ae693aaa 836 cec_command::Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_REPORT_PHYSICAL_ADDRESS);
8fa35473
LOK
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
844bool CCECCommandHandler::TransmitPoll(const cec_logical_address iInitiator, const cec_logical_address iDestination)
845{
846 cec_command command;
ae693aaa 847 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_NONE);
8fa35473 848
ae693aaa 849 return Transmit(command, false);
8fa35473
LOK
850}
851
852bool CCECCommandHandler::TransmitPowerState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_power_status state)
853{
854 cec_command command;
ae693aaa 855 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_REPORT_POWER_STATUS);
8fa35473
LOK
856 command.parameters.PushBack((uint8_t) state);
857
858 return Transmit(command);
859}
860
861bool CCECCommandHandler::TransmitVendorID(const cec_logical_address iInitiator, uint64_t iVendorId)
862{
863 cec_command command;
ae693aaa 864 cec_command::Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_DEVICE_VENDOR_ID);
8fa35473
LOK
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
873bool CCECCommandHandler::TransmitAudioStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint8_t state)
874{
875 cec_command command;
ae693aaa 876 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_REPORT_AUDIO_STATUS);
8fa35473
LOK
877 command.parameters.PushBack(state);
878
879 return Transmit(command);
880}
881
882bool CCECCommandHandler::TransmitSetSystemAudioMode(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state)
883{
884 cec_command command;
ae693aaa 885 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SET_SYSTEM_AUDIO_MODE);
8fa35473
LOK
886 command.parameters.PushBack((uint8_t)state);
887
888 return Transmit(command);
889}
890
891bool CCECCommandHandler::TransmitSystemAudioModeStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state)
892{
893 cec_command command;
ae693aaa 894 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS);
8fa35473
LOK
895 command.parameters.PushBack((uint8_t)state);
896
897 return Transmit(command);
898}
899
900bool CCECCommandHandler::TransmitDeckStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_deck_info state)
901{
902 cec_command command;
ae693aaa 903 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_DECK_STATUS);
8fa35473
LOK
904 command.PushBack((uint8_t)state);
905
906 return Transmit(command);
907}
908
4bec9d79 909bool CCECCommandHandler::TransmitKeypress(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */)
8fa35473
LOK
910{
911 cec_command command;
ae693aaa 912 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_USER_CONTROL_PRESSED);
8fa35473
LOK
913 command.parameters.PushBack((uint8_t)key);
914
4bec9d79 915 return Transmit(command, bWait);
8fa35473
LOK
916}
917
4bec9d79 918bool CCECCommandHandler::TransmitKeyRelease(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWait /* = true */)
8fa35473
LOK
919{
920 cec_command command;
ae693aaa 921 cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_USER_CONTROL_RELEASE);
8fa35473 922
4bec9d79 923 return Transmit(command, bWait);
8fa35473
LOK
924}
925
ae693aaa 926bool CCECCommandHandler::Transmit(cec_command &command, bool bExpectResponse /* = true */)
8fa35473 927{
ae693aaa 928 command.transmit_timeout = m_iTransmitTimeout;
ae693aaa 929
8fa35473 930 CLockObject writeLock(&m_processor->m_transmitMutex);
6359ffd1 931 CLockObject receiveLock(&m_receiveMutex);
8fa35473 932 if (m_processor->Transmit(command))
ae693aaa
LOK
933 {
934 if (bExpectResponse)
6359ffd1 935 return m_condition.Wait(&m_receiveMutex, m_iTransmitWait);
ae693aaa
LOK
936 return true;
937 }
8fa35473
LOK
938
939 return false;
940}
83be0701
LOK
941
942bool CCECCommandHandler::InitHandler(void)
943{
944 if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV)
945 {
842262d8 946 CCECBusDevice *primary = m_processor->GetPrimaryDevice();
6b1eea98
LOK
947 primary->SetPowerStatus(CEC_POWER_STATUS_ON);
948 primary->SetMenuState(CEC_MENU_STATE_ACTIVATED);
949
89a726fa
LOK
950 if (m_processor->GetPrimaryDevice()->GetPhysicalAddress(false) != 0xffff)
951 {
952 m_processor->SetActiveSource();
953 primary->TransmitMenuState(m_busDevice->GetLogicalAddress());
954 m_bHandlerInited = true;
955 }
83be0701 956 }
7dc58c9f 957 return true;
83be0701 958}