cec: removed deprecated CECCreate() method
[deb_libcec.git] / src / lib / CECProcessor.cpp
CommitLineData
abbca718
LOK
1/*
2 * This file is part of the libCEC(R) library.
3 *
b492c10e 4 * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
abbca718
LOK
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
2abe74eb 33#include "CECProcessor.h"
abbca718 34
7bb4ed43 35#include "adapter/USBCECAdapterCommunication.h"
eafa9d46 36#include "devices/CECBusDevice.h"
51b2a094
LOK
37#include "devices/CECAudioSystem.h"
38#include "devices/CECPlaybackDevice.h"
39#include "devices/CECRecordingDevice.h"
40#include "devices/CECTuner.h"
41#include "devices/CECTV.h"
62f5527d 42#include "implementations/CECCommandHandler.h"
2abe74eb 43#include "LibCEC.h"
ba65909d 44#include "platform/util/timeutils.h"
abbca718
LOK
45
46using namespace CEC;
47using namespace std;
f00ff009 48using namespace PLATFORM;
abbca718 49
1113cb7d 50CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, const cec_device_type_list &types) :
b64db02e 51 m_bInitialised(false),
16b1e052 52 m_iHDMIPort(CEC_DEFAULT_HDMI_PORT),
d2f1c157 53 m_iBaseDevice((cec_logical_address)CEC_DEFAULT_BASE_DEVICE),
f8513317
LOK
54 m_strDeviceName(strDeviceName),
55 m_types(types),
99666519 56 m_communication(NULL),
f8513317 57 m_controller(controller),
dcd240b2
LOK
58 m_bMonitor(false),
59 m_iStandardLineTimeout(3),
5f316715
LOK
60 m_iRetryLineTimeout(3),
61 m_iLastTransmission(0)
f8513317 62{
ab1469a0 63 m_logicalAddresses.Clear();
f8513317 64 for (int iPtr = 0; iPtr < 16; iPtr++)
51b2a094
LOK
65 {
66 switch(iPtr)
67 {
68 case CECDEVICE_AUDIOSYSTEM:
5d5a2dc2 69 m_busDevices[iPtr] = new CCECAudioSystem(this, (cec_logical_address) iPtr, 0xFFFF);
51b2a094
LOK
70 break;
71 case CECDEVICE_PLAYBACKDEVICE1:
72 case CECDEVICE_PLAYBACKDEVICE2:
73 case CECDEVICE_PLAYBACKDEVICE3:
5d5a2dc2 74 m_busDevices[iPtr] = new CCECPlaybackDevice(this, (cec_logical_address) iPtr, 0xFFFF);
51b2a094
LOK
75 break;
76 case CECDEVICE_RECORDINGDEVICE1:
77 case CECDEVICE_RECORDINGDEVICE2:
78 case CECDEVICE_RECORDINGDEVICE3:
5d5a2dc2 79 m_busDevices[iPtr] = new CCECRecordingDevice(this, (cec_logical_address) iPtr, 0xFFFF);
51b2a094
LOK
80 break;
81 case CECDEVICE_TUNER1:
82 case CECDEVICE_TUNER2:
83 case CECDEVICE_TUNER3:
84 case CECDEVICE_TUNER4:
5d5a2dc2 85 m_busDevices[iPtr] = new CCECTuner(this, (cec_logical_address) iPtr, 0xFFFF);
51b2a094
LOK
86 break;
87 case CECDEVICE_TV:
88 m_busDevices[iPtr] = new CCECTV(this, (cec_logical_address) iPtr, 0);
89 break;
90 default:
5d5a2dc2 91 m_busDevices[iPtr] = new CCECBusDevice(this, (cec_logical_address) iPtr, 0xFFFF);
51b2a094
LOK
92 break;
93 }
94 }
f8513317
LOK
95}
96
2abe74eb 97CCECProcessor::~CCECProcessor(void)
abbca718 98{
eca71746 99 Close();
7c63a480 100
d1998c7b
LOK
101 for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
102 delete m_busDevices[iPtr];
abbca718
LOK
103}
104
eca71746
LOK
105void CCECProcessor::Close(void)
106{
107 StopThread();
108
109 CLockObject lock(m_mutex);
110 if (m_communication)
111 {
112 m_communication->Close();
113 delete m_communication;
114 m_communication = NULL;
115 }
116}
117
578c3905 118bool CCECProcessor::OpenConnection(const char *strPort, uint16_t iBaudRate, uint32_t iTimeoutMs)
abbca718 119{
a674fd68 120 bool bReturn(false);
578c3905 121 CLockObject lock(m_mutex);
99666519 122 if (m_communication)
578c3905 123 {
9f9c8c82
LOK
124 CLibCEC::AddLog(CEC_LOG_WARNING, "existing connection handler found, deleting it");
125 m_communication->Close();
126 delete m_communication;
578c3905 127 }
1113cb7d 128
7bb4ed43 129 m_communication = new CUSBCECAdapterCommunication(this, strPort, iBaudRate);
99666519 130
578c3905
LOK
131 /* check for an already opened connection */
132 if (m_communication->IsOpen())
1113cb7d 133 {
5477a250 134 CLibCEC::AddLog(CEC_LOG_ERROR, "connection already opened");
578c3905
LOK
135 return bReturn;
136 }
abbca718 137
c520af4f
LOK
138 uint64_t iNow = GetTimeMs();
139 uint64_t iTarget = iTimeoutMs > 0 ? iNow + iTimeoutMs : iNow + CEC_DEFAULT_TRANSMIT_WAIT;
140
578c3905 141 /* open a new connection */
efed01e1
LOK
142 unsigned iConnectTry(0);
143 while (iNow < iTarget && (bReturn = m_communication->Open(this, iTimeoutMs)) == false)
3d78df91
LOK
144 {
145 CLibCEC::AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry);
146 Sleep(500);
147 iNow = GetTimeMs();
148 }
56035c86 149
efed01e1
LOK
150 if (bReturn)
151 CLibCEC::AddLog(CEC_LOG_NOTICE, "connected to the CEC adapter. firmware version = %d", m_communication->GetFirmwareVersion());
3d78df91 152
578c3905
LOK
153 return bReturn;
154}
155
0cfdeb5a
LOK
156bool CCECProcessor::IsInitialised(void)
157{
158 CLockObject lock(m_mutex);
159 return m_bInitialised;
160}
161
2db8981f 162void CCECProcessor::SetInitialised(bool bSetTo /* = true */)
578c3905 163{
578c3905 164 CLockObject lock(m_mutex);
2db8981f
LOK
165 m_bInitialised = bSetTo;
166}
578c3905 167
2db8981f
LOK
168bool CCECProcessor::Initialise(void)
169{
170 bool bReturn(false);
578c3905 171 {
2db8981f
LOK
172 CLockObject lock(m_mutex);
173 if (!m_logicalAddresses.IsEmpty())
174 m_logicalAddresses.Clear();
578c3905 175
2db8981f
LOK
176 if (!FindLogicalAddresses())
177 {
5477a250 178 CLibCEC::AddLog(CEC_LOG_ERROR, "could not detect our logical addresses");
2db8981f
LOK
179 return bReturn;
180 }
181
182 /* only set our OSD name for the primary device */
183 m_busDevices[m_logicalAddresses.primary]->m_strDeviceName = m_strDeviceName;
184 }
578c3905
LOK
185
186 /* get the vendor id from the TV, so we are using the correct handler */
187 m_busDevices[CECDEVICE_TV]->RequestVendorId();
188 ReplaceHandlers();
189
190 if ((bReturn = SetHDMIPort(m_iBaseDevice, m_iHDMIPort, true)) == false)
5477a250 191 CLibCEC::AddLog(CEC_LOG_ERROR, "unable to set HDMI port %d on %s (%x)", m_iHDMIPort, ToString(m_iBaseDevice), (uint8_t)m_iBaseDevice);
2db8981f
LOK
192
193 SetInitialised(bReturn);
578c3905
LOK
194
195 return bReturn;
196}
197
198bool CCECProcessor::Start(const char *strPort, uint16_t iBaudRate /* = 38400 */, uint32_t iTimeoutMs /* = 10000 */)
199{
200 bool bReturn(false);
201
202 {
203 CLockObject lock(m_mutex);
204 if (!OpenConnection(strPort, iBaudRate, iTimeoutMs))
a674fd68 205 return bReturn;
994dbaaa 206
a674fd68 207 /* create the processor thread */
8e57f83c 208 if (!CreateThread())
a674fd68 209 {
5477a250 210 CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a processor thread");
a674fd68 211 return bReturn;
994dbaaa 212 }
a674fd68
LOK
213 }
214
578c3905 215 if ((bReturn = Initialise()) == false)
a674fd68 216 {
5477a250 217 CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a processor thread");
578c3905 218 StopThread(true);
a674fd68
LOK
219 }
220 else
221 {
5477a250 222 CLibCEC::AddLog(CEC_LOG_DEBUG, "processor thread started");
a674fd68
LOK
223 }
224
225 return bReturn;
abbca718
LOK
226}
227
b58d9277 228bool CCECProcessor::TryLogicalAddress(cec_logical_address address)
f8513317 229{
93fff5c1 230 if (m_busDevices[address]->TryLogicalAddress())
f8513317 231 {
ab1469a0 232 m_logicalAddresses.Set(address);
f8513317
LOK
233 return true;
234 }
235
f8513317
LOK
236 return false;
237}
238
b58d9277 239bool CCECProcessor::FindLogicalAddressRecordingDevice(void)
f8513317 240{
5477a250 241 CLibCEC::AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'recording device'");
b58d9277
LOK
242 return TryLogicalAddress(CECDEVICE_RECORDINGDEVICE1) ||
243 TryLogicalAddress(CECDEVICE_RECORDINGDEVICE2) ||
244 TryLogicalAddress(CECDEVICE_RECORDINGDEVICE3);
f8513317
LOK
245}
246
b58d9277 247bool CCECProcessor::FindLogicalAddressTuner(void)
f8513317 248{
5477a250 249 CLibCEC::AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'tuner'");
b58d9277
LOK
250 return TryLogicalAddress(CECDEVICE_TUNER1) ||
251 TryLogicalAddress(CECDEVICE_TUNER2) ||
252 TryLogicalAddress(CECDEVICE_TUNER3) ||
253 TryLogicalAddress(CECDEVICE_TUNER4);
f8513317
LOK
254}
255
b58d9277 256bool CCECProcessor::FindLogicalAddressPlaybackDevice(void)
f8513317 257{
5477a250 258 CLibCEC::AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'playback device'");
b58d9277
LOK
259 return TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE1) ||
260 TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE2) ||
261 TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE3);
f8513317
LOK
262}
263
b58d9277 264bool CCECProcessor::FindLogicalAddressAudioSystem(void)
f8513317 265{
5477a250 266 CLibCEC::AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'audio'");
b58d9277 267 return TryLogicalAddress(CECDEVICE_AUDIOSYSTEM);
f8513317
LOK
268}
269
3e61b350
LOK
270bool CCECProcessor::ChangeDeviceType(cec_device_type from, cec_device_type to)
271{
272 bool bChanged(false);
273
5477a250 274 CLibCEC::AddLog(CEC_LOG_NOTICE, "changing device type '%s' into '%s'", ToString(from), ToString(to));
3e61b350 275
f00ff009 276 CLockObject lock(m_mutex);
3e61b350
LOK
277 CCECBusDevice *previousDevice = GetDeviceByType(from);
278 m_logicalAddresses.primary = CECDEVICE_UNKNOWN;
279
280 for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
281 {
282 if (m_types.types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
283 continue;
284
285 if (m_types.types[iPtr] == from)
286 {
287 bChanged = true;
288 m_types.types[iPtr] = to;
289 }
290 else if (m_types.types[iPtr] == to && bChanged)
291 {
292 m_types.types[iPtr] = CEC_DEVICE_TYPE_RESERVED;
293 }
294 }
295
296 if (bChanged)
297 {
298 FindLogicalAddresses();
299
300 CCECBusDevice *newDevice = GetDeviceByType(to);
301 if (previousDevice && newDevice)
302 {
303 newDevice->SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
4478bc79 304 previousDevice->SetDeviceStatus(CEC_DEVICE_STATUS_NOT_PRESENT);
3e61b350
LOK
305
306 newDevice->SetCecVersion(previousDevice->GetCecVersion(false));
307 previousDevice->SetCecVersion(CEC_VERSION_UNKNOWN);
308
309 newDevice->SetMenuLanguage(previousDevice->GetMenuLanguage(false));
310 cec_menu_language lang;
311 lang.device = previousDevice->GetLogicalAddress();
312 for (unsigned int iPtr = 0; iPtr < 4; iPtr++)
313 lang.language[iPtr] = '?';
314 lang.language[3] = 0;
315 previousDevice->SetMenuLanguage(lang);
316
317 newDevice->SetMenuState(previousDevice->GetMenuState());
318 previousDevice->SetMenuState(CEC_MENU_STATE_DEACTIVATED);
319
320 newDevice->SetOSDName(previousDevice->GetOSDName(false));
321 previousDevice->SetOSDName(ToString(previousDevice->GetLogicalAddress()));
322
323 newDevice->SetPhysicalAddress(previousDevice->GetPhysicalAddress(false));
324 previousDevice->SetPhysicalAddress(0xFFFF);
325
326 newDevice->SetPowerStatus(previousDevice->GetPowerStatus(false));
327 previousDevice->SetPowerStatus(CEC_POWER_STATUS_UNKNOWN);
328
329 newDevice->SetVendorId(previousDevice->GetVendorId(false));
330 previousDevice->SetVendorId(CEC_VENDOR_UNKNOWN);
331
332 if ((from == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || from == CEC_DEVICE_TYPE_RECORDING_DEVICE) &&
333 (to == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || to == CEC_DEVICE_TYPE_RECORDING_DEVICE))
334 {
335 ((CCECPlaybackDevice *) newDevice)->SetDeckControlMode(((CCECPlaybackDevice *) previousDevice)->GetDeckControlMode());
336 ((CCECPlaybackDevice *) previousDevice)->SetDeckControlMode(CEC_DECK_CONTROL_MODE_STOP);
337
338 ((CCECPlaybackDevice *) newDevice)->SetDeckStatus(((CCECPlaybackDevice *) previousDevice)->GetDeckStatus());
339 ((CCECPlaybackDevice *) previousDevice)->SetDeckStatus(CEC_DECK_INFO_STOP);
340 }
341 }
342 }
343
344 return true;
345}
346
f8513317
LOK
347bool CCECProcessor::FindLogicalAddresses(void)
348{
349 bool bReturn(true);
ab1469a0 350 m_logicalAddresses.Clear();
f8513317
LOK
351
352 for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
353 {
354 if (m_types.types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
355 continue;
356
5477a250 357 CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - device %d: type %d", __FUNCTION__, iPtr, m_types.types[iPtr]);
f8513317
LOK
358
359 if (m_types.types[iPtr] == CEC_DEVICE_TYPE_RECORDING_DEVICE)
b58d9277 360 bReturn &= FindLogicalAddressRecordingDevice();
f8513317 361 if (m_types.types[iPtr] == CEC_DEVICE_TYPE_TUNER)
b58d9277 362 bReturn &= FindLogicalAddressTuner();
f8513317 363 if (m_types.types[iPtr] == CEC_DEVICE_TYPE_PLAYBACK_DEVICE)
b58d9277 364 bReturn &= FindLogicalAddressPlaybackDevice();
f8513317 365 if (m_types.types[iPtr] == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
b58d9277 366 bReturn &= FindLogicalAddressAudioSystem();
f8513317
LOK
367 }
368
a674fd68
LOK
369 if (bReturn)
370 SetAckMask(m_logicalAddresses.AckMask());
371
f8513317
LOK
372 return bReturn;
373}
374
a3ffc068
LOK
375void CCECProcessor::ReplaceHandlers(void)
376{
ded7e7ce 377 CLockObject lock(m_mutex);
0cfdeb5a
LOK
378 if (!IsInitialised())
379 return;
a3ffc068 380 for (uint8_t iPtr = 0; iPtr <= CECDEVICE_PLAYBACKDEVICE3; iPtr++)
591170fd 381 m_busDevices[iPtr]->ReplaceHandler(m_bInitialised);
a3ffc068
LOK
382}
383
b1f94db1
LOK
384bool CCECProcessor::OnCommandReceived(const cec_command &command)
385{
386 m_commandBuffer.Push(command);
387 return true;
388}
389
2abe74eb 390void *CCECProcessor::Process(void)
f99bc831 391{
8e57f83c
LOK
392 cec_command command;
393 CLibCEC::AddLog(CEC_LOG_DEBUG, "processor thread started");
abbca718 394
b1f94db1 395 while (!IsStopped() && m_communication->IsOpen())
abbca718 396 {
591170fd 397 ReplaceHandlers();
b1f94db1 398 if (m_commandBuffer.Pop(command))
9dee1670 399 ParseCommand(command);
b5f34cf9 400
13fd6a66 401 m_controller->CheckKeypressTimeout();
b1f94db1 402 Sleep(5);
abbca718
LOK
403 }
404
60fa4578 405 return NULL;
abbca718
LOK
406}
407
18203d17 408bool CCECProcessor::SetActiveSource(cec_device_type type /* = CEC_DEVICE_TYPE_RESERVED */)
abbca718 409{
8ac9c610
LOK
410 bool bReturn(false);
411
60fa4578 412 if (!IsRunning())
8ac9c610 413 return bReturn;
f99bc831 414
18203d17 415 cec_logical_address addr = m_logicalAddresses.primary;
04437dcf 416
18203d17
LOK
417 if (type != CEC_DEVICE_TYPE_RESERVED)
418 {
90ea9066 419 for (uint8_t iPtr = 0; iPtr <= 11; iPtr++)
18203d17
LOK
420 {
421 if (m_logicalAddresses[iPtr] && m_busDevices[iPtr]->m_type == type)
422 {
423 addr = (cec_logical_address) iPtr;
424 break;
425 }
426 }
427 }
428
37b0c572 429 m_busDevices[addr]->SetActiveSource();
d383d6d0 430 if (m_busDevices[addr]->GetPhysicalAddress(false) != 0xFFFF)
e046c7bf
LOK
431 {
432 bReturn = m_busDevices[addr]->TransmitActiveSource();
433
4478bc79
LOK
434 if (bReturn)
435 {
436 m_busDevices[addr]->SetMenuState(CEC_MENU_STATE_ACTIVATED);
437 m_busDevices[addr]->TransmitMenuState(CECDEVICE_TV);
438 }
439
e046c7bf
LOK
440 if (bReturn && (m_busDevices[addr]->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
441 m_busDevices[addr]->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE) &&
442 m_busDevices[addr]->GetHandler()->SendDeckStatusUpdateOnActiveSource())
443 {
444 bReturn = ((CCECPlaybackDevice *)m_busDevices[addr])->TransmitDeckStatus(CECDEVICE_TV);
445 }
446 }
8d915412
LOK
447
448 return bReturn;
18203d17
LOK
449}
450
37b0c572
LOK
451bool CCECProcessor::SetActiveSource(uint16_t iStreamPath)
452{
453 bool bReturn(false);
454
455 CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamPath);
456 if (device)
457 {
458 device->SetActiveSource();
459 bReturn = true;
460 }
461
462 return bReturn;
463}
464
dcd240b2
LOK
465void CCECProcessor::SetStandardLineTimeout(uint8_t iTimeout)
466{
f00ff009 467 CLockObject lock(m_mutex);
dcd240b2
LOK
468 m_iStandardLineTimeout = iTimeout;
469}
470
471void CCECProcessor::SetRetryLineTimeout(uint8_t iTimeout)
472{
f00ff009 473 CLockObject lock(m_mutex);
dcd240b2
LOK
474 m_iRetryLineTimeout = iTimeout;
475}
476
18203d17
LOK
477bool CCECProcessor::SetActiveView(void)
478{
4a870dc8 479 return SetActiveSource(m_types.IsEmpty() ? CEC_DEVICE_TYPE_RESERVED : m_types[0]);
8ac9c610
LOK
480}
481
28fa6c97 482bool CCECProcessor::SetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate /* = true */)
a9232a79
LOK
483{
484 bool bReturn(false);
485
486 CCECBusDevice *device = GetDeviceByType(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
487 if (device)
488 {
489 ((CCECPlaybackDevice *) device)->SetDeckControlMode(mode);
28fa6c97
LOK
490 if (bSendUpdate)
491 ((CCECPlaybackDevice *) device)->TransmitDeckStatus(CECDEVICE_TV);
a9232a79
LOK
492 bReturn = true;
493 }
494
495 return bReturn;
496}
497
28fa6c97 498bool CCECProcessor::SetDeckInfo(cec_deck_info info, bool bSendUpdate /* = true */)
a9232a79
LOK
499{
500 bool bReturn(false);
501
502 CCECBusDevice *device = GetDeviceByType(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
503 if (device)
504 {
505 ((CCECPlaybackDevice *) device)->SetDeckStatus(info);
28fa6c97
LOK
506 if (bSendUpdate)
507 ((CCECPlaybackDevice *) device)->TransmitDeckStatus(CECDEVICE_TV);
a9232a79
LOK
508 bReturn = true;
509 }
510
511 return bReturn;
512}
513
d2f1c157 514bool CCECProcessor::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort, bool bForce /* = false */)
16b1e052
LOK
515{
516 bool bReturn(false);
f00ff009 517 CLockObject lock(m_mutex);
16b1e052 518
89b3c9df
LOK
519 m_iBaseDevice = iBaseDevice;
520 m_iHDMIPort = iPort;
8e57f83c 521 if (!IsRunning() && !bForce)
89b3c9df 522 return true;
16b1e052 523
5477a250 524 CLibCEC::AddLog(CEC_LOG_DEBUG, "setting HDMI port to %d on device %s (%d)", iPort, ToString(iBaseDevice), (int)iBaseDevice);
56035c86 525
16b1e052 526 uint16_t iPhysicalAddress(0);
1e7afacd 527 if (iBaseDevice > CECDEVICE_TV)
5d0c1164 528 {
f00ff009 529 lock.Unlock();
1e7afacd 530 iPhysicalAddress = m_busDevices[iBaseDevice]->GetPhysicalAddress();
5d0c1164
LOK
531 lock.Lock();
532 }
1e7afacd 533
a674fd68 534 if (iPhysicalAddress < 0xffff)
1e7afacd 535 {
1e7afacd 536 if (iPhysicalAddress == 0)
5d355340 537 iPhysicalAddress += 0x1000 * iPort;
1e7afacd 538 else if (iPhysicalAddress % 0x1000 == 0)
5d355340 539 iPhysicalAddress += 0x100 * iPort;
1e7afacd 540 else if (iPhysicalAddress % 0x100 == 0)
5d355340 541 iPhysicalAddress += 0x10 * iPort;
1e7afacd 542 else if (iPhysicalAddress % 0x10 == 0)
5d355340 543 iPhysicalAddress += iPort;
1e7afacd 544
5d355340 545 bReturn = true;
16b1e052
LOK
546 }
547
a674fd68 548 if (!bReturn)
5477a250 549 CLibCEC::AddLog(CEC_LOG_ERROR, "failed to set the physical address");
f070564b
LOK
550 else
551 {
f00ff009 552 lock.Unlock();
f070564b
LOK
553 SetPhysicalAddress(iPhysicalAddress);
554 }
a674fd68 555
16b1e052
LOK
556 return bReturn;
557}
558
45b97de7 559bool CCECProcessor::PhysicalAddressInUse(uint16_t iPhysicalAddress)
16b1e052 560{
9fd73dd4 561 for (unsigned int iPtr = 0; iPtr < 15; iPtr++)
16b1e052
LOK
562 {
563 if (m_busDevices[iPtr]->GetPhysicalAddress(false) == iPhysicalAddress)
564 return true;
565 }
566 return false;
567}
568
ab27363d 569bool CCECProcessor::TransmitInactiveSource(void)
abbca718 570{
60fa4578 571 if (!IsRunning())
f99bc831
LOK
572 return false;
573
ab1469a0 574 if (!m_logicalAddresses.IsEmpty() && m_busDevices[m_logicalAddresses.primary])
ab27363d 575 return m_busDevices[m_logicalAddresses.primary]->TransmitInactiveSource();
cc60ab1c 576 return false;
abbca718
LOK
577}
578
9dee1670 579void CCECProcessor::LogOutput(const cec_command &data)
abbca718 580{
1d3ca3de 581 CStdString strTx;
57f45e6c
LOK
582 strTx.Format("<< %02x", ((uint8_t)data.initiator << 4) + (uint8_t)data.destination);
583 if (data.opcode_set)
584 strTx.AppendFormat(":%02x", (uint8_t)data.opcode);
9dee1670 585
06a1f7ce 586 for (uint8_t iPtr = 0; iPtr < data.parameters.size; iPtr++)
1d3ca3de 587 strTx.AppendFormat(":%02x", data.parameters[iPtr]);
5477a250 588 CLibCEC::AddLog(CEC_LOG_TRAFFIC, strTx.c_str());
9dee1670 589}
2abe74eb 590
06bfd4d7 591bool CCECProcessor::SetLogicalAddress(cec_logical_address iLogicalAddress)
abbca718 592{
f00ff009 593 CLockObject lock(m_mutex);
f8513317 594 if (m_logicalAddresses.primary != iLogicalAddress)
06775107 595 {
5477a250 596 CLibCEC::AddLog(CEC_LOG_NOTICE, "<< setting primary logical address to %1x", iLogicalAddress);
f8513317 597 m_logicalAddresses.primary = iLogicalAddress;
ab1469a0
LOK
598 m_logicalAddresses.Set(iLogicalAddress);
599 return SetAckMask(m_logicalAddresses.AckMask());
06775107 600 }
2abe74eb 601
06bfd4d7 602 return true;
abbca718 603}
825ddb96 604
28fa6c97
LOK
605bool CCECProcessor::SetMenuState(cec_menu_state state, bool bSendUpdate /* = true */)
606{
607 for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
608 {
609 if (m_logicalAddresses[iPtr])
610 m_busDevices[iPtr]->SetMenuState(state);
611 }
612
613 if (bSendUpdate)
614 m_busDevices[m_logicalAddresses.primary]->TransmitMenuState(CECDEVICE_TV);
615
616 return true;
617}
618
bebb19dc 619bool CCECProcessor::SetPhysicalAddress(uint16_t iPhysicalAddress, bool bSendUpdate /* = true */)
2492216a 620{
f070564b
LOK
621 bool bSendActiveView(false);
622 bool bReturn(false);
4d6f5ac7 623 cec_logical_addresses sendUpdatesTo;
ded7e7ce 624 sendUpdatesTo.Clear();
ff684fef 625
f070564b 626 {
f00ff009 627 CLockObject lock(m_mutex);
f070564b
LOK
628 if (!m_logicalAddresses.IsEmpty())
629 {
630 bool bWasActiveSource(false);
631 for (uint8_t iPtr = 0; iPtr < 15; iPtr++)
632 if (m_logicalAddresses[iPtr])
633 {
634 bWasActiveSource |= m_busDevices[iPtr]->IsActiveSource();
635 m_busDevices[iPtr]->SetInactiveSource();
636 m_busDevices[iPtr]->SetPhysicalAddress(iPhysicalAddress);
637 if (bSendUpdate)
4d6f5ac7 638 sendUpdatesTo.Set((cec_logical_address)iPtr);
f070564b
LOK
639 }
640
641 bSendActiveView = bWasActiveSource && bSendUpdate;
642 bReturn = true;
643 }
cc60ab1c 644 }
f070564b 645
4d6f5ac7
LOK
646 for (uint8_t iPtr = 0; iPtr < 15; iPtr++)
647 if (sendUpdatesTo[iPtr])
648 m_busDevices[iPtr]->TransmitPhysicalAddress();
649
f070564b
LOK
650 if (bSendActiveView)
651 SetActiveView();
652
653 return bReturn;
1969b140
LOK
654}
655
8b7e5ff6
LOK
656bool CCECProcessor::SwitchMonitoring(bool bEnable)
657{
5477a250 658 CLibCEC::AddLog(CEC_LOG_NOTICE, "== %s monitoring mode ==", bEnable ? "enabling" : "disabling");
8b7e5ff6 659
855a3a98 660 {
f00ff009 661 CLockObject lock(m_mutex);
855a3a98 662 m_bMonitor = bEnable;
855a3a98
LOK
663 }
664
8b7e5ff6 665 if (bEnable)
06bfd4d7 666 return SetAckMask(0);
8b7e5ff6 667 else
ab1469a0 668 return SetAckMask(m_logicalAddresses.AckMask());
8b7e5ff6
LOK
669}
670
57f45e6c
LOK
671bool CCECProcessor::PollDevice(cec_logical_address iAddress)
672{
673 if (iAddress != CECDEVICE_UNKNOWN && m_busDevices[iAddress])
95a73fa7
LOK
674 {
675 return m_logicalAddresses.primary == CECDEVICE_UNKNOWN ?
676 m_busDevices[iAddress]->TransmitPoll(iAddress) :
677 m_busDevices[m_logicalAddresses.primary]->TransmitPoll(iAddress);
678 }
57f45e6c
LOK
679 return false;
680}
681
5c73f7f7 682uint8_t CCECProcessor::VolumeUp(bool bSendRelease /* = true */)
04e637f9
LOK
683{
684 uint8_t status = 0;
37b0c572 685 if (IsPresentDevice(CECDEVICE_AUDIOSYSTEM))
5c73f7f7 686 status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->VolumeUp(bSendRelease);
04e637f9
LOK
687
688 return status;
689}
690
5c73f7f7 691uint8_t CCECProcessor::VolumeDown(bool bSendRelease /* = true */)
04e637f9
LOK
692{
693 uint8_t status = 0;
37b0c572 694 if (IsPresentDevice(CECDEVICE_AUDIOSYSTEM))
5c73f7f7 695 status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->VolumeDown(bSendRelease);
04e637f9
LOK
696
697 return status;
698}
699
5c73f7f7 700uint8_t CCECProcessor::MuteAudio(bool bSendRelease /* = true */)
04e637f9
LOK
701{
702 uint8_t status = 0;
37b0c572 703 if (IsPresentDevice(CECDEVICE_AUDIOSYSTEM))
5c73f7f7 704 status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->MuteAudio(bSendRelease);
04e637f9
LOK
705
706 return status;
707}
708
16b1e052 709CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bRefresh /* = false */) const
8ac9c610 710{
16b1e052 711 if (m_busDevices[m_logicalAddresses.primary]->GetPhysicalAddress(false) == iPhysicalAddress)
b58d9277 712 return m_busDevices[m_logicalAddresses.primary];
8ac9c610 713
b58d9277 714 CCECBusDevice *device = NULL;
8ac9c610
LOK
715 for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
716 {
16b1e052 717 if (m_busDevices[iPtr]->GetPhysicalAddress(bRefresh) == iPhysicalAddress)
8ac9c610
LOK
718 {
719 device = m_busDevices[iPtr];
720 break;
721 }
722 }
723
724 return device;
725}
726
a9232a79
LOK
727CCECBusDevice *CCECProcessor::GetDeviceByType(cec_device_type type) const
728{
729 CCECBusDevice *device = NULL;
730
7619faad 731 for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
a9232a79 732 {
b64db02e 733 if (m_busDevices[iPtr]->m_type == type && m_logicalAddresses[iPtr])
a9232a79
LOK
734 {
735 device = m_busDevices[iPtr];
736 break;
737 }
738 }
739
740 return device;
741}
742
842262d8
LOK
743CCECBusDevice *CCECProcessor::GetPrimaryDevice(void) const
744{
745 CCECBusDevice *device(NULL);
746 cec_logical_address primary = m_logicalAddresses.primary;
747 if (primary != CECDEVICE_UNKNOWN)
748 device = m_busDevices[primary];
749 return device;
750}
751
6a1c0009
LOK
752cec_version CCECProcessor::GetDeviceCecVersion(cec_logical_address iAddress)
753{
754 return m_busDevices[iAddress]->GetCecVersion();
755}
756
ed21be2a
LOK
757cec_osd_name CCECProcessor::GetDeviceOSDName(cec_logical_address iAddress)
758{
759 CStdString strOSDName = m_busDevices[iAddress]->GetOSDName();
760 cec_osd_name retVal;
761
762 snprintf(retVal.name, sizeof(retVal.name), "%s", strOSDName.c_str());
763 retVal.device = iAddress;
764
765 return retVal;
766}
767
a3269a0a
LOK
768bool CCECProcessor::GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu_language *language)
769{
cc60ab1c
LOK
770 if (m_busDevices[iAddress])
771 {
772 *language = m_busDevices[iAddress]->GetMenuLanguage();
5744fbba 773 return (strcmp(language->language, "???") != 0);
cc60ab1c
LOK
774 }
775 return false;
a3269a0a
LOK
776}
777
44c74256
LOK
778uint64_t CCECProcessor::GetDeviceVendorId(cec_logical_address iAddress)
779{
cc60ab1c
LOK
780 if (m_busDevices[iAddress])
781 return m_busDevices[iAddress]->GetVendorId();
782 return false;
44c74256
LOK
783}
784
eab72c40
LOK
785uint16_t CCECProcessor::GetDevicePhysicalAddress(cec_logical_address iAddress)
786{
787 if (m_busDevices[iAddress])
788 return m_busDevices[iAddress]->GetPhysicalAddress(false);
789 return false;
790}
791
e55f3f70
LOK
792cec_power_status CCECProcessor::GetDevicePowerStatus(cec_logical_address iAddress)
793{
cc60ab1c
LOK
794 if (m_busDevices[iAddress])
795 return m_busDevices[iAddress]->GetPowerStatus();
796 return CEC_POWER_STATUS_UNKNOWN;
e55f3f70
LOK
797}
798
b4b1b49b
LOK
799cec_logical_address CCECProcessor::GetActiveSource(void)
800{
801 for (uint8_t iPtr = 0; iPtr <= 11; iPtr++)
802 {
803 if (m_busDevices[iPtr]->IsActiveSource())
804 return (cec_logical_address)iPtr;
805 }
806
807 return CECDEVICE_UNKNOWN;
808}
809
810bool CCECProcessor::IsActiveSource(cec_logical_address iAddress)
811{
812 return m_busDevices[iAddress]->IsActiveSource();
813}
814
8d84e2c0 815bool CCECProcessor::Transmit(const cec_command &data)
825ddb96 816{
7bb4ed43 817 cec_adapter_message_state retVal(ADAPTER_MESSAGE_STATE_UNKNOWN);
eb35e4ca 818 {
7bb4ed43
LOK
819 CLockObject lock(m_mutex);
820 LogOutput(data);
5f316715 821 m_iLastTransmission = GetTimeMs();
7bb4ed43
LOK
822 if (!m_communication)
823 return false;
824 uint8_t iMaxTries = m_busDevices[data.initiator]->GetHandler()->GetTransmitRetries() + 1;
825 retVal = m_communication->Write(data, iMaxTries, m_iLineTimeout, m_iRetryLineTimeout);
2abe74eb
LOK
826 }
827
7bb4ed43
LOK
828 /* set to "not present" on failed ack */
829 if (retVal == ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED &&
830 data.destination != CECDEVICE_BROADCAST)
831 m_busDevices[data.destination]->SetDeviceStatus(CEC_DEVICE_STATUS_NOT_PRESENT);
9902f4e8 832
7bb4ed43 833 return retVal == ADAPTER_MESSAGE_STATE_SENT_ACKED;
825ddb96 834}
abbca718 835
22b4e74a 836void CCECProcessor::TransmitAbort(cec_logical_address address, cec_opcode opcode, cec_abort_reason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */)
abbca718 837{
5477a250 838 CLibCEC::AddLog(CEC_LOG_DEBUG, "<< transmitting abort message");
9dee1670 839
06a1f7ce 840 cec_command command;
f8513317 841 // TODO
ab1469a0
LOK
842 cec_command::Format(command, m_logicalAddresses.primary, address, CEC_OPCODE_FEATURE_ABORT);
843 command.parameters.PushBack((uint8_t)opcode);
844 command.parameters.PushBack((uint8_t)reason);
9dee1670
LOK
845
846 Transmit(command);
abbca718
LOK
847}
848
b1f94db1 849void CCECProcessor::ParseCommand(const cec_command &command)
abbca718 850{
e9de9629 851 CStdString dataStr;
1d3ca3de 852 dataStr.Format(">> %1x%1x:%02x", command.initiator, command.destination, command.opcode);
e9de9629
LOK
853 for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++)
854 dataStr.AppendFormat(":%02x", (unsigned int)command.parameters[iPtr]);
5477a250 855 CLibCEC::AddLog(CEC_LOG_TRAFFIC, dataStr.c_str());
dc113aca 856
7871d66e 857 if (!m_bMonitor && command.initiator >= CECDEVICE_TV && command.initiator <= CECDEVICE_BROADCAST)
e9de9629 858 m_busDevices[(uint8_t)command.initiator]->HandleCommand(command);
dc113aca
LOK
859}
860
6d858ba4
LOK
861cec_logical_addresses CCECProcessor::GetActiveDevices(void)
862{
863 cec_logical_addresses addresses;
988de7b9 864 addresses.Clear();
6d858ba4
LOK
865 for (unsigned int iPtr = 0; iPtr < 15; iPtr++)
866 {
867 if (m_busDevices[iPtr]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
868 addresses.Set((cec_logical_address) iPtr);
869 }
870 return addresses;
871}
872
37b0c572 873bool CCECProcessor::IsPresentDevice(cec_logical_address address)
6d858ba4
LOK
874{
875 return m_busDevices[address]->GetStatus() == CEC_DEVICE_STATUS_PRESENT;
876}
877
37b0c572 878bool CCECProcessor::IsPresentDeviceType(cec_device_type type)
6d858ba4 879{
6d858ba4 880 for (unsigned int iPtr = 0; iPtr < 15; iPtr++)
2813bd07
LOK
881 {
882 if (m_busDevices[iPtr]->GetType() == type && m_busDevices[iPtr]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
6d858ba4 883 return true;
2813bd07
LOK
884 }
885
6d858ba4
LOK
886 return false;
887}
888
0f23c85c
LOK
889uint16_t CCECProcessor::GetPhysicalAddress(void) const
890{
ab1469a0 891 if (!m_logicalAddresses.IsEmpty() && m_busDevices[m_logicalAddresses.primary])
16b1e052 892 return m_busDevices[m_logicalAddresses.primary]->GetPhysicalAddress(false);
cc60ab1c 893 return false;
0f23c85c
LOK
894}
895
06bfd4d7
LOK
896bool CCECProcessor::SetAckMask(uint16_t iMask)
897{
5dcf9f25 898 return m_communication->SetAckMask(iMask);
06bfd4d7 899}
a33794d8 900
4bec9d79 901bool CCECProcessor::TransmitKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */)
a33794d8 902{
86869f8f 903 return m_busDevices[iDestination]->TransmitKeypress(key, bWait);
a33794d8
LOK
904}
905
4bec9d79 906bool CCECProcessor::TransmitKeyRelease(cec_logical_address iDestination, bool bWait /* = true */)
a33794d8 907{
86869f8f 908 return m_busDevices[iDestination]->TransmitKeyRelease(bWait);
a33794d8 909}
7c63a480 910
3e61b350
LOK
911const char *CCECProcessor::ToString(const cec_device_type type)
912{
913 switch (type)
914 {
915 case CEC_DEVICE_TYPE_AUDIO_SYSTEM:
916 return "audio system";
917 case CEC_DEVICE_TYPE_PLAYBACK_DEVICE:
918 return "playback device";
919 case CEC_DEVICE_TYPE_RECORDING_DEVICE:
920 return "recording device";
921 case CEC_DEVICE_TYPE_RESERVED:
922 return "reserved";
923 case CEC_DEVICE_TYPE_TUNER:
924 return "tuner";
925 case CEC_DEVICE_TYPE_TV:
926 return "TV";
927 default:
928 return "unknown";
929 }
930}
931
03ae897d
LOK
932const char *CCECProcessor::ToString(const cec_menu_state state)
933{
934 switch (state)
935 {
936 case CEC_MENU_STATE_ACTIVATED:
937 return "activated";
938 case CEC_MENU_STATE_DEACTIVATED:
939 return "deactivated";
940 default:
941 return "unknown";
942 }
943}
944
945const char *CCECProcessor::ToString(const cec_version version)
946{
947 switch (version)
948 {
949 case CEC_VERSION_1_2:
950 return "1.2";
951 case CEC_VERSION_1_2A:
952 return "1.2a";
953 case CEC_VERSION_1_3:
954 return "1.3";
955 case CEC_VERSION_1_3A:
956 return "1.3a";
957 case CEC_VERSION_1_4:
958 return "1.4";
959 default:
960 return "unknown";
961 }
962}
963
964const char *CCECProcessor::ToString(const cec_power_status status)
965{
966 switch (status)
967 {
968 case CEC_POWER_STATUS_ON:
969 return "on";
970 case CEC_POWER_STATUS_STANDBY:
971 return "standby";
972 case CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY:
973 return "in transition from on to standby";
974 case CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON:
975 return "in transition from standby to on";
976 default:
977 return "unknown";
978 }
979}
980
981const char *CCECProcessor::ToString(const cec_logical_address address)
982{
983 switch(address)
984 {
985 case CECDEVICE_AUDIOSYSTEM:
986 return "Audio";
987 case CECDEVICE_BROADCAST:
988 return "Broadcast";
989 case CECDEVICE_FREEUSE:
990 return "Free use";
991 case CECDEVICE_PLAYBACKDEVICE1:
992 return "Playback 1";
993 case CECDEVICE_PLAYBACKDEVICE2:
994 return "Playback 2";
995 case CECDEVICE_PLAYBACKDEVICE3:
996 return "Playback 3";
997 case CECDEVICE_RECORDINGDEVICE1:
998 return "Recorder 1";
999 case CECDEVICE_RECORDINGDEVICE2:
1000 return "Recorder 2";
1001 case CECDEVICE_RECORDINGDEVICE3:
1002 return "Recorder 3";
1003 case CECDEVICE_RESERVED1:
1004 return "Reserved 1";
1005 case CECDEVICE_RESERVED2:
1006 return "Reserved 2";
1007 case CECDEVICE_TUNER1:
1008 return "Tuner 1";
1009 case CECDEVICE_TUNER2:
1010 return "Tuner 2";
1011 case CECDEVICE_TUNER3:
1012 return "Tuner 3";
1013 case CECDEVICE_TUNER4:
1014 return "Tuner 4";
1015 case CECDEVICE_TV:
1016 return "TV";
1017 default:
1018 return "unknown";
1019 }
1020}
1021
1022const char *CCECProcessor::ToString(const cec_deck_control_mode mode)
1023{
1024 switch (mode)
1025 {
1026 case CEC_DECK_CONTROL_MODE_SKIP_FORWARD_WIND:
1027 return "skip forward wind";
1028 case CEC_DECK_CONTROL_MODE_EJECT:
1029 return "eject";
1030 case CEC_DECK_CONTROL_MODE_SKIP_REVERSE_REWIND:
1031 return "reverse rewind";
1032 case CEC_DECK_CONTROL_MODE_STOP:
1033 return "stop";
1034 default:
1035 return "unknown";
1036 }
1037}
1038
1039const char *CCECProcessor::ToString(const cec_deck_info status)
1040{
1041 switch (status)
1042 {
1043 case CEC_DECK_INFO_PLAY:
1044 return "play";
1045 case CEC_DECK_INFO_RECORD:
1046 return "record";
1047 case CEC_DECK_INFO_PLAY_REVERSE:
1048 return "play reverse";
1049 case CEC_DECK_INFO_STILL:
1050 return "still";
1051 case CEC_DECK_INFO_SLOW:
1052 return "slow";
1053 case CEC_DECK_INFO_SLOW_REVERSE:
1054 return "slow reverse";
1055 case CEC_DECK_INFO_FAST_FORWARD:
1056 return "fast forward";
1057 case CEC_DECK_INFO_FAST_REVERSE:
1058 return "fast reverse";
1059 case CEC_DECK_INFO_NO_MEDIA:
1060 return "no media";
1061 case CEC_DECK_INFO_STOP:
1062 return "stop";
1063 case CEC_DECK_INFO_SKIP_FORWARD_WIND:
1064 return "info skip forward wind";
1065 case CEC_DECK_INFO_SKIP_REVERSE_REWIND:
1066 return "info skip reverse rewind";
1067 case CEC_DECK_INFO_INDEX_SEARCH_FORWARD:
1068 return "info index search forward";
1069 case CEC_DECK_INFO_INDEX_SEARCH_REVERSE:
1070 return "info index search reverse";
1071 case CEC_DECK_INFO_OTHER_STATUS:
1072 return "other";
1073 default:
1074 return "unknown";
1075 }
1076}
1077
1078const char *CCECProcessor::ToString(const cec_opcode opcode)
1079{
1080 switch (opcode)
1081 {
1082 case CEC_OPCODE_ACTIVE_SOURCE:
1083 return "active source";
1084 case CEC_OPCODE_IMAGE_VIEW_ON:
1085 return "image view on";
1086 case CEC_OPCODE_TEXT_VIEW_ON:
1087 return "text view on";
1088 case CEC_OPCODE_INACTIVE_SOURCE:
1089 return "inactive source";
1090 case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
1091 return "request active source";
1092 case CEC_OPCODE_ROUTING_CHANGE:
1093 return "routing change";
1094 case CEC_OPCODE_ROUTING_INFORMATION:
1095 return "routing information";
1096 case CEC_OPCODE_SET_STREAM_PATH:
1097 return "set stream path";
1098 case CEC_OPCODE_STANDBY:
1099 return "standby";
1100 case CEC_OPCODE_RECORD_OFF:
1101 return "record off";
1102 case CEC_OPCODE_RECORD_ON:
1103 return "record on";
1104 case CEC_OPCODE_RECORD_STATUS:
1105 return "record status";
1106 case CEC_OPCODE_RECORD_TV_SCREEN:
1107 return "record tv screen";
1108 case CEC_OPCODE_CLEAR_ANALOGUE_TIMER:
1109 return "clear analogue timer";
1110 case CEC_OPCODE_CLEAR_DIGITAL_TIMER:
1111 return "clear digital timer";
1112 case CEC_OPCODE_CLEAR_EXTERNAL_TIMER:
1113 return "clear external timer";
1114 case CEC_OPCODE_SET_ANALOGUE_TIMER:
1115 return "set analogue timer";
1116 case CEC_OPCODE_SET_DIGITAL_TIMER:
1117 return "set digital timer";
1118 case CEC_OPCODE_SET_EXTERNAL_TIMER:
1119 return "set external timer";
1120 case CEC_OPCODE_SET_TIMER_PROGRAM_TITLE:
1121 return "set timer program title";
1122 case CEC_OPCODE_TIMER_CLEARED_STATUS:
1123 return "timer cleared status";
1124 case CEC_OPCODE_TIMER_STATUS:
1125 return "timer status";
1126 case CEC_OPCODE_CEC_VERSION:
1127 return "cec version";
1128 case CEC_OPCODE_GET_CEC_VERSION:
1129 return "get cec version";
1130 case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
1131 return "give physical address";
1132 case CEC_OPCODE_GET_MENU_LANGUAGE:
1133 return "get menu language";
1134 case CEC_OPCODE_REPORT_PHYSICAL_ADDRESS:
1135 return "report physical address";
1136 case CEC_OPCODE_SET_MENU_LANGUAGE:
1137 return "set menu language";
1138 case CEC_OPCODE_DECK_CONTROL:
1139 return "deck control";
1140 case CEC_OPCODE_DECK_STATUS:
1141 return "deck status";
1142 case CEC_OPCODE_GIVE_DECK_STATUS:
1143 return "give deck status";
1144 case CEC_OPCODE_PLAY:
1145 return "play";
1146 case CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS:
1147 return "give tuner status";
1148 case CEC_OPCODE_SELECT_ANALOGUE_SERVICE:
1149 return "select analogue service";
1150 case CEC_OPCODE_SELECT_DIGITAL_SERVICE:
1151 return "set digital service";
1152 case CEC_OPCODE_TUNER_DEVICE_STATUS:
1153 return "tuner device status";
1154 case CEC_OPCODE_TUNER_STEP_DECREMENT:
1155 return "tuner step decrement";
1156 case CEC_OPCODE_TUNER_STEP_INCREMENT:
1157 return "tuner step increment";
1158 case CEC_OPCODE_DEVICE_VENDOR_ID:
1159 return "device vendor id";
1160 case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
1161 return "give device vendor id";
1162 case CEC_OPCODE_VENDOR_COMMAND:
1163 return "vendor command";
1164 case CEC_OPCODE_VENDOR_COMMAND_WITH_ID:
1165 return "vendor command with id";
1166 case CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN:
1167 return "vendor remote button down";
1168 case CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP:
1169 return "vendor remote button up";
1170 case CEC_OPCODE_SET_OSD_STRING:
1171 return "set osd string";
1172 case CEC_OPCODE_GIVE_OSD_NAME:
1173 return "give osd name";
1174 case CEC_OPCODE_SET_OSD_NAME:
1175 return "set osd name";
1176 case CEC_OPCODE_MENU_REQUEST:
1177 return "menu request";
1178 case CEC_OPCODE_MENU_STATUS:
1179 return "menu status";
1180 case CEC_OPCODE_USER_CONTROL_PRESSED:
1181 return "user control pressed";
1182 case CEC_OPCODE_USER_CONTROL_RELEASE:
1183 return "user control release";
1184 case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
1185 return "give device power status";
1186 case CEC_OPCODE_REPORT_POWER_STATUS:
1187 return "report power status";
1188 case CEC_OPCODE_FEATURE_ABORT:
1189 return "feature abort";
1190 case CEC_OPCODE_ABORT:
1191 return "abort";
1192 case CEC_OPCODE_GIVE_AUDIO_STATUS:
1193 return "give audio status";
1194 case CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS:
1195 return "give audio mode status";
1196 case CEC_OPCODE_REPORT_AUDIO_STATUS:
1197 return "report audio status";
1198 case CEC_OPCODE_SET_SYSTEM_AUDIO_MODE:
1199 return "set system audio mode";
1200 case CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST:
1201 return "system audio mode request";
1202 case CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS:
1203 return "system audio mode status";
1204 case CEC_OPCODE_SET_AUDIO_RATE:
1205 return "set audio rate";
1206 default:
1207 return "UNKNOWN";
1208 }
1209}
1210
1211const char *CCECProcessor::ToString(const cec_system_audio_status mode)
1212{
1213 switch(mode)
1214 {
1215 case CEC_SYSTEM_AUDIO_STATUS_ON:
1216 return "on";
1217 case CEC_SYSTEM_AUDIO_STATUS_OFF:
1218 return "off";
1219 default:
1220 return "unknown";
1221 }
1222}
1223
1de6617c 1224const char *CCECProcessor::ToString(const cec_audio_status UNUSED(status))
03ae897d
LOK
1225{
1226 // TODO this is a mask
1227 return "TODO";
1228}
1229
1230const char *CCECProcessor::ToString(const cec_vendor_id vendor)
1231{
1232 switch (vendor)
1233 {
1234 case CEC_VENDOR_SAMSUNG:
1235 return "Samsung";
1236 case CEC_VENDOR_LG:
1237 return "LG";
1238 case CEC_VENDOR_PANASONIC:
1239 return "Panasonic";
1240 case CEC_VENDOR_PIONEER:
1241 return "Pioneer";
1242 case CEC_VENDOR_ONKYO:
1243 return "Onkyo";
1244 case CEC_VENDOR_YAMAHA:
1245 return "Yamaha";
ec0deac1
LOK
1246 case CEC_VENDOR_PHILIPS:
1247 return "Philips";
1a87cacc
LOK
1248 case CEC_VENDOR_SONY:
1249 return "Sony";
03ae897d
LOK
1250 default:
1251 return "Unknown";
1252 }
1253}
1254
7c63a480
LOK
1255void *CCECBusScan::Process(void)
1256{
1257 CCECBusDevice *device(NULL);
fe6f8e37 1258 uint8_t iCounter(0);
5f316715 1259
5e5637c6 1260 while (!IsStopped())
7c63a480 1261 {
bdb0f7f4 1262 if (++iCounter < 10)
fe6f8e37
LOK
1263 {
1264 Sleep(1000);
1265 continue;
1266 }
5f316715 1267 for (unsigned int iPtr = 0; iPtr <= 11 && !IsStopped(); iPtr++)
7c63a480 1268 {
5f316715
LOK
1269 device = m_processor->m_busDevices[iPtr];
1270 WaitUntilIdle();
1271 if (device && device->GetStatus(true) == CEC_DEVICE_STATUS_PRESENT)
5e5637c6 1272 {
5f316715
LOK
1273 WaitUntilIdle();
1274 if (!IsStopped())
1275 device->GetVendorId();
1276
1277 WaitUntilIdle();
1278 if (!IsStopped())
1279 device->GetPowerStatus(true);
5e5637c6 1280 }
7c63a480
LOK
1281 }
1282 }
5f316715 1283
7c63a480
LOK
1284 return NULL;
1285}
1113cb7d 1286
5f316715
LOK
1287void CCECBusScan::WaitUntilIdle(void)
1288{
1289 if (IsStopped())
1290 return;
1291
701f753b 1292 int32_t iWaitTime = 3000 - (int32_t)(GetTimeMs() - m_processor->GetLastTransmission());
5f316715
LOK
1293 while (iWaitTime > 0)
1294 {
1295 Sleep(iWaitTime);
701f753b 1296 iWaitTime = 3000 - (int32_t)(GetTimeMs() - m_processor->GetLastTransmission());
5f316715
LOK
1297 }
1298}
1299
1113cb7d
LOK
1300bool CCECProcessor::StartBootloader(void)
1301{
1302 return m_communication->StartBootloader();
1303}
1304
1305bool CCECProcessor::PingAdapter(void)
1306{
1307 return m_communication->PingAdapter();
1308}
6729ac71
LOK
1309
1310void CCECProcessor::HandlePoll(cec_logical_address initiator, cec_logical_address destination)
1311{
0cfdeb5a 1312 m_busDevices[initiator]->HandlePoll(destination);
6729ac71
LOK
1313}
1314
7bb4ed43 1315bool CCECProcessor::HandleReceiveFailed(cec_logical_address initiator)
6729ac71 1316{
0cfdeb5a 1317 return !m_busDevices[initiator]->HandleReceiveFailed();
6729ac71 1318}
f42d3e0f
LOK
1319
1320bool CCECProcessor::SetStreamPath(uint16_t iPhysicalAddress)
1321{
1322 // stream path changes are sent by the TV
1323 return m_busDevices[CECDEVICE_TV]->GetHandler()->TransmitSetStreamPath(iPhysicalAddress);
1324}