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