Imported Upstream version 2.2.0
[deb_libcec.git] / src / lib / CECProcessor.cpp
CommitLineData
cbbe90dd
JB
1/*
2 * This file is part of the libCEC(R) library.
3 *
4 * libCEC(R) is Copyright (C) 2011-2013 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 "env.h"
34#include "CECProcessor.h"
35
36#include "adapter/AdapterFactory.h"
37#include "devices/CECBusDevice.h"
38#include "devices/CECAudioSystem.h"
39#include "devices/CECPlaybackDevice.h"
40#include "devices/CECRecordingDevice.h"
41#include "devices/CECTuner.h"
42#include "devices/CECTV.h"
43#include "implementations/CECCommandHandler.h"
44#include "LibCEC.h"
45#include "CECClient.h"
46#include "CECTypeUtils.h"
47#include "platform/util/timeutils.h"
48#include "platform/util/util.h"
49
50using namespace CEC;
51using namespace std;
52using namespace PLATFORM;
53
54#define CEC_PROCESSOR_SIGNAL_WAIT_TIME 1000
55#define ACTIVE_SOURCE_CHECK_INTERVAL 500
56#define TV_PRESENT_CHECK_INTERVAL 30000
57
58#define ToString(x) CCECTypeUtils::ToString(x)
59
60CCECStandbyProtection::CCECStandbyProtection(CCECProcessor* processor) :
61 m_processor(processor) {}
62CCECStandbyProtection::~CCECStandbyProtection(void) {}
63
64void* CCECStandbyProtection::Process(void)
65{
66 int64_t last = GetTimeMs();
67 int64_t next;
68 while (!IsStopped())
69 {
70 PLATFORM::CEvent::Sleep(1000);
71
72 next = GetTimeMs();
73
74 // reset the connection if the clock changed
75 if (next < last || next - last > 10000)
76 {
77 libcec_parameter param;
78 param.paramData = NULL; param.paramType = CEC_PARAMETER_TYPE_UNKOWN;
79 m_processor->GetLib()->Alert(CEC_ALERT_CONNECTION_LOST, param);
80 break;
81 }
82
83 last = next;
84 }
85 return NULL;
86}
87
88CCECProcessor::CCECProcessor(CLibCEC *libcec) :
89 m_bInitialised(false),
90 m_communication(NULL),
91 m_libcec(libcec),
92 m_iStandardLineTimeout(3),
93 m_iRetryLineTimeout(3),
94 m_iLastTransmission(0),
95 m_bMonitor(true),
96 m_addrAllocator(NULL),
97 m_bStallCommunication(false),
98 m_connCheck(NULL)
99{
100 m_busDevices = new CCECDeviceMap(this);
101}
102
103CCECProcessor::~CCECProcessor(void)
104{
105 m_bStallCommunication = false;
106 DELETE_AND_NULL(m_addrAllocator);
107 Close();
108 DELETE_AND_NULL(m_busDevices);
109}
110
111bool CCECProcessor::Start(const char *strPort, uint16_t iBaudRate /* = CEC_SERIAL_DEFAULT_BAUDRATE */, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
112{
113 CLockObject lock(m_mutex);
114 // open a connection
115 if (!OpenConnection(strPort, iBaudRate, iTimeoutMs))
116 return false;
117
118 // create the processor thread
119 if (!IsRunning())
120 {
121 if (!CreateThread())
122 {
123 m_libcec->AddLog(CEC_LOG_ERROR, "could not create a processor thread");
124 return false;
125 }
126 }
127
128 return true;
129}
130
131void CCECProcessor::Close(void)
132{
133 // mark as uninitialised
134 SetCECInitialised(false);
135
136 // stop the processor
137 DELETE_AND_NULL(m_connCheck);
138 StopThread(-1);
139 m_inBuffer.Broadcast();
140 StopThread();
141
142 // close the connection
143 CLockObject lock(m_mutex);
144 DELETE_AND_NULL(m_communication);
145}
146
147void CCECProcessor::ResetMembers(void)
148{
149 // close the connection
150 DELETE_AND_NULL(m_communication);
151
152 // reset the other members to the initial state
153 m_iStandardLineTimeout = 3;
154 m_iRetryLineTimeout = 3;
155 m_iLastTransmission = 0;
156 m_busDevices->ResetDeviceStatus();
157}
158
159bool CCECProcessor::OpenConnection(const char *strPort, uint16_t iBaudRate, uint32_t iTimeoutMs, bool bStartListening /* = true */)
160{
161 bool bReturn(false);
162 CTimeout timeout(iTimeoutMs > 0 ? iTimeoutMs : CEC_DEFAULT_TRANSMIT_WAIT);
163
164 // ensure that a previous connection is closed
165 Close();
166
167 // reset all member to the initial state
168 ResetMembers();
169
170 // check whether the Close() method deleted any previous connection
171 if (m_communication)
172 {
173 m_libcec->AddLog(CEC_LOG_ERROR, "previous connection could not be closed");
174 return bReturn;
175 }
176
177 // create a new connection
178 m_communication = CAdapterFactory(this->m_libcec).GetInstance(strPort, iBaudRate);
179
180 // open a new connection
181 unsigned iConnectTry(0);
182 while (timeout.TimeLeft() > 0 && (bReturn = m_communication->Open((timeout.TimeLeft() / CEC_CONNECT_TRIES), false, bStartListening)) == false)
183 {
184 m_libcec->AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry);
185 m_communication->Close();
186 CEvent::Sleep(CEC_DEFAULT_CONNECT_RETRY_WAIT);
187 }
188
189 m_libcec->AddLog(CEC_LOG_NOTICE, "connection opened");
190
191 // mark as initialised
192 SetCECInitialised(true);
193
194 return bReturn;
195}
196
197bool CCECProcessor::CECInitialised(void)
198{
199 CLockObject lock(m_threadMutex);
200 return m_bInitialised;
201}
202
203void CCECProcessor::SetCECInitialised(bool bSetTo /* = true */)
204{
205 {
206 CLockObject lock(m_mutex);
207 m_bInitialised = bSetTo;
208 }
209 if (!bSetTo)
210 UnregisterClients();
211}
212
213bool CCECProcessor::TryLogicalAddress(cec_logical_address address, cec_version libCECSpecVersion /* = CEC_VERSION_1_4 */)
214{
215 // find the device
216 CCECBusDevice *device = m_busDevices->At(address);
217 if (device)
218 {
219 // check if it's already marked as present or used
220 if (device->IsPresent() || device->IsHandledByLibCEC())
221 return false;
222
223 // poll the LA if not
224 return device->TryLogicalAddress(libCECSpecVersion);
225 }
226
227 return false;
228}
229
230void CCECProcessor::ReplaceHandlers(void)
231{
232 if (!CECInitialised())
233 return;
234
235 // check each device
236 for (CECDEVICEMAP::iterator it = m_busDevices->Begin(); it != m_busDevices->End(); it++)
237 it->second->ReplaceHandler(true);
238}
239
240bool CCECProcessor::OnCommandReceived(const cec_command &command)
241{
242 return m_inBuffer.Push(command);
243}
244
245void *CCECProcessor::Process(void)
246{
247 m_libcec->AddLog(CEC_LOG_DEBUG, "processor thread started");
248
249 if (!m_connCheck)
250 m_connCheck = new CCECStandbyProtection(this);
251 m_connCheck->CreateThread();
252
253 cec_command command; command.Clear();
254 CTimeout activeSourceCheck(ACTIVE_SOURCE_CHECK_INTERVAL);
255 CTimeout tvPresentCheck(TV_PRESENT_CHECK_INTERVAL);
256
257 // as long as we're not being stopped and the connection is open
258 while (!IsStopped() && m_communication->IsOpen())
259 {
260 // wait for a new incoming command, and process it
261 if (m_inBuffer.Pop(command, CEC_PROCESSOR_SIGNAL_WAIT_TIME))
262 ProcessCommand(command);
263
264 if (CECInitialised() && !IsStopped())
265 {
266 // check clients for keypress timeouts
267 m_libcec->CheckKeypressTimeout();
268
269 // check if we need to replace handlers
270 ReplaceHandlers();
271
272 // check whether we need to activate a source, if it failed before
273 if (activeSourceCheck.TimeLeft() == 0)
274 {
275 if (CECInitialised())
276 TransmitPendingActiveSourceCommands();
277 activeSourceCheck.Init(ACTIVE_SOURCE_CHECK_INTERVAL);
278 }
279
280 // check whether the TV is present and responding
281 if (tvPresentCheck.TimeLeft() == 0)
282 {
283 CCECClient *primary = GetPrimaryClient();
284 // only check whether the tv responds to polls when a client is connected and not in monitoring mode
285 if (primary && primary->GetConfiguration()->bMonitorOnly != 1)
286 {
287 if (!m_busDevices->At(CECDEVICE_TV)->IsPresent())
288 {
289 libcec_parameter param;
290 param.paramType = CEC_PARAMETER_TYPE_STRING;
291 param.paramData = (void*)"TV does not respond to CEC polls";
292 primary->Alert(CEC_ALERT_TV_POLL_FAILED, param);
293 }
294 }
295 tvPresentCheck.Init(TV_PRESENT_CHECK_INTERVAL);
296 }
297 }
298 }
299
300 return NULL;
301}
302
303bool CCECProcessor::ActivateSource(uint16_t iStreamPath)
304{
305 bool bReturn(false);
306
307 // find the device with the given PA
308 CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamPath);
309 // and make it the active source when found
310 if (device)
311 bReturn = device->ActivateSource();
312 else
313 m_libcec->AddLog(CEC_LOG_DEBUG, "device with PA '%04x' not found", iStreamPath);
314
315 return bReturn;
316}
317
318void CCECProcessor::SetActiveSource(bool bSetTo, bool bClientUnregistered)
319{
320 if (m_communication)
321 m_communication->SetActiveSource(bSetTo, bClientUnregistered);
322}
323
324void CCECProcessor::SetStandardLineTimeout(uint8_t iTimeout)
325{
326 CLockObject lock(m_mutex);
327 m_iStandardLineTimeout = iTimeout;
328}
329
330uint8_t CCECProcessor::GetStandardLineTimeout(void)
331{
332 CLockObject lock(m_mutex);
333 return m_iStandardLineTimeout;
334}
335
336void CCECProcessor::SetRetryLineTimeout(uint8_t iTimeout)
337{
338 CLockObject lock(m_mutex);
339 m_iRetryLineTimeout = iTimeout;
340}
341
342uint8_t CCECProcessor::GetRetryLineTimeout(void)
343{
344 CLockObject lock(m_mutex);
345 return m_iRetryLineTimeout;
346}
347
348bool CCECProcessor::PhysicalAddressInUse(uint16_t iPhysicalAddress)
349{
350 CCECBusDevice *device = GetDeviceByPhysicalAddress(iPhysicalAddress);
351 return device != NULL;
352}
353
354void CCECProcessor::LogOutput(const cec_command &data)
355{
356 CStdString strTx;
357
358 // initiator and destination
359 strTx.Format("<< %02x", ((uint8_t)data.initiator << 4) + (uint8_t)data.destination);
360
361 // append the opcode
362 if (data.opcode_set)
363 strTx.AppendFormat(":%02x", (uint8_t)data.opcode);
364
365 // append the parameters
366 for (uint8_t iPtr = 0; iPtr < data.parameters.size; iPtr++)
367 strTx.AppendFormat(":%02x", data.parameters[iPtr]);
368
369 // and log it
370 m_libcec->AddLog(CEC_LOG_TRAFFIC, strTx.c_str());
371}
372
373bool CCECProcessor::PollDevice(cec_logical_address iAddress)
374{
375 // try to find the primary device
376 CCECBusDevice *primary = GetPrimaryDevice();
377 // poll the destination, with the primary as source
378 if (primary)
379 return primary->TransmitPoll(iAddress, true);
380
381 CCECBusDevice *device = m_busDevices->At(CECDEVICE_UNREGISTERED);
382 if (device)
383 return device->TransmitPoll(iAddress, true);
384
385 return false;
386}
387
388CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bSuppressUpdate /* = true */)
389{
390 return m_busDevices ?
391 m_busDevices->GetDeviceByPhysicalAddress(iPhysicalAddress, bSuppressUpdate) :
392 NULL;
393}
394
395CCECBusDevice *CCECProcessor::GetDevice(cec_logical_address address) const
396{
397 return m_busDevices ?
398 m_busDevices->At(address) :
399 NULL;
400}
401
402cec_logical_address CCECProcessor::GetActiveSource(bool bRequestActiveSource /* = true */)
403{
404 // get the device that is marked as active source from the device map
405 CCECBusDevice *activeSource = m_busDevices->GetActiveSource();
406 if (activeSource)
407 return activeSource->GetLogicalAddress();
408
409 if (bRequestActiveSource)
410 {
411 // request the active source from the bus
412 CCECBusDevice *primary = GetPrimaryDevice();
413 if (primary)
414 {
415 primary->RequestActiveSource();
416 return GetActiveSource(false);
417 }
418 }
419
420 // unknown or none
421 return CECDEVICE_UNKNOWN;
422}
423
424bool CCECProcessor::IsActiveSource(cec_logical_address iAddress)
425{
426 CCECBusDevice *device = m_busDevices->At(iAddress);
427 return device && device->IsActiveSource();
428}
429
430bool CCECProcessor::Transmit(const cec_command &data, bool bIsReply)
431{
432 cec_command transmitData(data);
433 uint8_t iMaxTries(0);
434 bool bRetry(true);
435 uint8_t iTries(0);
436
437 // get the current timeout setting
438 uint8_t iLineTimeout(GetStandardLineTimeout());
439
440 // reset the state of this message to 'unknown'
441 cec_adapter_message_state adapterState = ADAPTER_MESSAGE_STATE_UNKNOWN;
442
443 CLockObject lock(m_mutex);
444 if (!m_communication)
445 return false;
446
447 if (!m_communication->SupportsSourceLogicalAddress(transmitData.initiator))
448 {
449 if (transmitData.initiator == CECDEVICE_UNREGISTERED && m_communication->SupportsSourceLogicalAddress(CECDEVICE_FREEUSE))
450 {
451 m_libcec->AddLog(CEC_LOG_DEBUG, "initiator '%s' is not supported by the CEC adapter. using '%s' instead", ToString(transmitData.initiator), ToString(CECDEVICE_FREEUSE));
452 transmitData.initiator = CECDEVICE_FREEUSE;
453 }
454 else
455 {
456 m_libcec->AddLog(CEC_LOG_DEBUG, "initiator '%s' is not supported by the CEC adapter", ToString(transmitData.initiator));
457 return false;
458 }
459 }
460
461 LogOutput(transmitData);
462
463 // find the initiator device
464 CCECBusDevice *initiator = m_busDevices->At(transmitData.initiator);
465 if (!initiator)
466 {
467 m_libcec->AddLog(CEC_LOG_WARNING, "invalid initiator");
468 return false;
469 }
470
471 // find the destination device, if it's not the broadcast address
472 if (transmitData.destination != CECDEVICE_BROADCAST)
473 {
474 // check if the device is marked as handled by libCEC
475 CCECBusDevice *destination = m_busDevices->At(transmitData.destination);
476 if (destination && destination->IsHandledByLibCEC())
477 {
478 // and reject the command if it's trying to send data to a device that is handled by libCEC
479 m_libcec->AddLog(CEC_LOG_WARNING, "not sending data to myself!");
480 return false;
481 }
482 }
483
484 // wait until we finished allocating a new LA if it got lost
485 lock.Unlock();
486 while (m_bStallCommunication) Sleep(5);
487 lock.Lock();
488
489 m_iLastTransmission = GetTimeMs();
490 // set the number of tries
491 iMaxTries = initiator->GetHandler()->GetTransmitRetries() + 1;
492 initiator->MarkHandlerReady();
493
494 // and try to send the command
495 while (bRetry && ++iTries < iMaxTries)
496 {
497 if (initiator->IsUnsupportedFeature(transmitData.opcode))
498 return false;
499
500 adapterState = !IsStopped() && m_communication && m_communication->IsOpen() ?
501 m_communication->Write(transmitData, bRetry, iLineTimeout, bIsReply) :
502 ADAPTER_MESSAGE_STATE_ERROR;
503 iLineTimeout = m_iRetryLineTimeout;
504 }
505
506 return bIsReply ?
507 adapterState == ADAPTER_MESSAGE_STATE_SENT_ACKED || adapterState == ADAPTER_MESSAGE_STATE_SENT || adapterState == ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT :
508 adapterState == ADAPTER_MESSAGE_STATE_SENT_ACKED;
509}
510
511void CCECProcessor::TransmitAbort(cec_logical_address source, cec_logical_address destination, cec_opcode opcode, cec_abort_reason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */)
512{
513 m_libcec->AddLog(CEC_LOG_DEBUG, "<< transmitting abort message");
514
515 cec_command command;
516 cec_command::Format(command, source, destination, CEC_OPCODE_FEATURE_ABORT);
517 command.parameters.PushBack((uint8_t)opcode);
518 command.parameters.PushBack((uint8_t)reason);
519
520 Transmit(command, true);
521}
522
523void CCECProcessor::ProcessCommand(const cec_command &command)
524{
525 // log the command
526 m_libcec->AddLog(CEC_LOG_TRAFFIC, ToString(command).c_str());
527
528 // find the initiator
529 CCECBusDevice *device = m_busDevices->At(command.initiator);
530
531 if (device)
532 device->HandleCommand(command);
533}
534
535bool CCECProcessor::IsPresentDevice(cec_logical_address address)
536{
537 CCECBusDevice *device = m_busDevices->At(address);
538 return device && device->GetStatus() == CEC_DEVICE_STATUS_PRESENT;
539}
540
541bool CCECProcessor::IsPresentDeviceType(cec_device_type type)
542{
543 CECDEVICEVEC devices;
544 m_busDevices->GetByType(type, devices);
545 CCECDeviceMap::FilterActive(devices);
546 return !devices.empty();
547}
548
549uint16_t CCECProcessor::GetDetectedPhysicalAddress(void) const
550{
551 return m_communication ? m_communication->GetPhysicalAddress() : CEC_INVALID_PHYSICAL_ADDRESS;
552}
553
554bool CCECProcessor::ClearLogicalAddresses(void)
555{
556 cec_logical_addresses addresses; addresses.Clear();
557 return SetLogicalAddresses(addresses);
558}
559
560bool CCECProcessor::SetLogicalAddresses(const cec_logical_addresses &addresses)
561{
562 return m_communication ? m_communication->SetLogicalAddresses(addresses) : false;
563}
564
565bool CCECProcessor::StandbyDevices(const cec_logical_address initiator, const CECDEVICEVEC &devices)
566{
567 bool bReturn(true);
568 for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
569 bReturn &= (*it)->Standby(initiator);
570 return bReturn;
571}
572
573bool CCECProcessor::StandbyDevice(const cec_logical_address initiator, cec_logical_address address)
574{
575 CCECBusDevice *device = m_busDevices->At(address);
576 return device ? device->Standby(initiator) : false;
577}
578
579bool CCECProcessor::PowerOnDevices(const cec_logical_address initiator, const CECDEVICEVEC &devices)
580{
581 bool bReturn(true);
582 for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
583 bReturn &= (*it)->PowerOn(initiator);
584 return bReturn;
585}
586
587bool CCECProcessor::PowerOnDevice(const cec_logical_address initiator, cec_logical_address address)
588{
589 CCECBusDevice *device = m_busDevices->At(address);
590 return device ? device->PowerOn(initiator) : false;
591}
592
593bool CCECProcessor::StartBootloader(const char *strPort /* = NULL */)
594{
595 bool bReturn(false);
596 // open a connection if no connection has been opened
597 if (!m_communication && strPort)
598 {
599 CAdapterFactory factory(this->m_libcec);
600 IAdapterCommunication *comm = factory.GetInstance(strPort);
601 CTimeout timeout(CEC_DEFAULT_CONNECT_TIMEOUT);
602 int iConnectTry(0);
603 while (timeout.TimeLeft() > 0 && (bReturn = comm->Open(timeout.TimeLeft() / CEC_CONNECT_TRIES, true)) == false)
604 {
605 m_libcec->AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry);
606 comm->Close();
607 Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
608 }
609 if (comm->IsOpen())
610 {
611 bReturn = comm->StartBootloader();
612 DELETE_AND_NULL(comm);
613 }
614 return bReturn;
615 }
616 else
617 {
618 m_communication->StartBootloader();
619 Close();
620 bReturn = true;
621 }
622
623 return bReturn;
624}
625
626bool CCECProcessor::PingAdapter(void)
627{
628 return m_communication->PingAdapter();
629}
630
631void CCECProcessor::HandlePoll(cec_logical_address initiator, cec_logical_address destination)
632{
633 CCECBusDevice *device = m_busDevices->At(destination);
634 if (device)
635 device->HandlePollFrom(initiator);
636}
637
638bool CCECProcessor::HandleReceiveFailed(cec_logical_address initiator)
639{
640 CCECBusDevice *device = m_busDevices->At(initiator);
641 return !device || !device->HandleReceiveFailed();
642}
643
644bool CCECProcessor::CanPersistConfiguration(void)
645{
646 return m_communication ? m_communication->GetFirmwareVersion() >= 2 : false;
647}
648
649bool CCECProcessor::PersistConfiguration(const libcec_configuration &configuration)
650{
651 libcec_configuration persistConfiguration = configuration;
652 if (!CLibCEC::IsValidPhysicalAddress(configuration.iPhysicalAddress))
653 {
654 CCECBusDevice *device = GetPrimaryDevice();
655 if (device)
656 persistConfiguration.iPhysicalAddress = device->GetCurrentPhysicalAddress();
657 }
658
659 return m_communication ? m_communication->PersistConfiguration(persistConfiguration) : false;
660}
661
662void CCECProcessor::RescanActiveDevices(void)
663{
664 for (CECDEVICEMAP::iterator it = m_busDevices->Begin(); it != m_busDevices->End(); it++)
665 it->second->GetStatus(true);
666}
667
668bool CCECProcessor::GetDeviceInformation(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
669{
670 if (!OpenConnection(strPort, CEC_SERIAL_DEFAULT_BAUDRATE, iTimeoutMs, false))
671 return false;
672
673 config->iFirmwareVersion = m_communication->GetFirmwareVersion();
674 config->iPhysicalAddress = m_communication->GetPhysicalAddress();
675 config->iFirmwareBuildDate = m_communication->GetFirmwareBuildDate();
676 config->adapterType = m_communication->GetAdapterType();
677
678 Close();
679
680 return true;
681}
682
683bool CCECProcessor::TransmitPendingActiveSourceCommands(void)
684{
685 bool bReturn(true);
686 for (CECDEVICEMAP::iterator it = m_busDevices->Begin(); it != m_busDevices->End(); it++)
687 bReturn &= it->second->TransmitPendingActiveSourceCommands();
688 return bReturn;
689}
690
691CCECTV *CCECProcessor::GetTV(void) const
692{
693 return CCECBusDevice::AsTV(m_busDevices->At(CECDEVICE_TV));
694}
695
696CCECAudioSystem *CCECProcessor::GetAudioSystem(void) const
697{
698 return CCECBusDevice::AsAudioSystem(m_busDevices->At(CECDEVICE_AUDIOSYSTEM));
699}
700
701CCECPlaybackDevice *CCECProcessor::GetPlaybackDevice(cec_logical_address address) const
702{
703 return CCECBusDevice::AsPlaybackDevice(m_busDevices->At(address));
704}
705
706CCECRecordingDevice *CCECProcessor::GetRecordingDevice(cec_logical_address address) const
707{
708 return CCECBusDevice::AsRecordingDevice(m_busDevices->At(address));
709}
710
711CCECTuner *CCECProcessor::GetTuner(cec_logical_address address) const
712{
713 return CCECBusDevice::AsTuner(m_busDevices->At(address));
714}
715
716bool CCECProcessor::AllocateLogicalAddresses(CCECClient* client)
717{
718 libcec_configuration &configuration = *client->GetConfiguration();
719
720 // mark as unregistered
721 client->SetRegistered(false);
722
723 // unregister this client from the old addresses
724 CECDEVICEVEC devices;
725 m_busDevices->GetByLogicalAddresses(devices, configuration.logicalAddresses);
726 for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
727 {
728 // remove client entry
729 CLockObject lock(m_mutex);
730 m_clients.erase((*it)->GetLogicalAddress());
731 }
732
733 // find logical addresses for this client
734 if (!client->AllocateLogicalAddresses())
735 {
736 m_libcec->AddLog(CEC_LOG_ERROR, "failed to find a free logical address for the client");
737 return false;
738 }
739
740 // register this client on the new addresses
741 devices.clear();
742 m_busDevices->GetByLogicalAddresses(devices, configuration.logicalAddresses);
743 for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
744 {
745 // set the physical address of the device at this LA
746 if (CLibCEC::IsValidPhysicalAddress(configuration.iPhysicalAddress))
747 (*it)->SetPhysicalAddress(configuration.iPhysicalAddress);
748
749 // replace a previous client
750 CLockObject lock(m_mutex);
751 m_clients.erase((*it)->GetLogicalAddress());
752 m_clients.insert(make_pair((*it)->GetLogicalAddress(), client));
753 }
754
755 // set the new ackmask
756 SetLogicalAddresses(GetLogicalAddresses());
757
758 // resume outgoing communication
759 m_bStallCommunication = false;
760
761 return true;
762}
763
764uint16_t CCECProcessor::GetPhysicalAddressFromEeprom(void)
765{
766 libcec_configuration config; config.Clear();
767 if (m_communication)
768 m_communication->GetConfiguration(config);
769 return config.iPhysicalAddress;
770}
771
772bool CCECProcessor::RegisterClient(CCECClient *client)
773{
774 if (!client)
775 return false;
776
777 libcec_configuration &configuration = *client->GetConfiguration();
778
779 if (configuration.clientVersion < CEC_CLIENT_VERSION_2_0_0)
780 {
781 m_libcec->AddLog(CEC_LOG_ERROR, "failed to register a new CEC client: client version %s is no longer supported", ToString((cec_client_version)configuration.clientVersion));
782 return false;
783 }
784
785 if (configuration.bMonitorOnly == 1)
786 return true;
787
788 if (!CECInitialised())
789 {
790 m_libcec->AddLog(CEC_LOG_ERROR, "failed to register a new CEC client: CEC processor is not initialised");
791 return false;
792 }
793
794 // unregister the client first if it's already been marked as registered
795 if (client->IsRegistered())
796 UnregisterClient(client);
797
798 // ensure that controlled mode is enabled
799 m_communication->SetControlledMode(true);
800 m_bMonitor = false;
801
802 // source logical address for requests
803 cec_logical_address sourceAddress(CECDEVICE_UNREGISTERED);
804 if (!m_communication->SupportsSourceLogicalAddress(CECDEVICE_UNREGISTERED))
805 {
806 if (m_communication->SupportsSourceLogicalAddress(CECDEVICE_FREEUSE))
807 sourceAddress = CECDEVICE_FREEUSE;
808 else
809 {
810 m_libcec->AddLog(CEC_LOG_ERROR, "failed to register a new CEC client: both unregistered and free use are not supported by the device");
811 return false;
812 }
813 }
814
815 // ensure that we know the vendor id of the TV
816 CCECBusDevice *tv = GetTV();
817 cec_vendor_id tvVendor(tv->GetVendorId(sourceAddress));
818
819 // wait until the handler is replaced, to avoid double registrations
820 if (tvVendor != CEC_VENDOR_UNKNOWN &&
821 CCECCommandHandler::HasSpecificHandler(tvVendor))
822 {
823 while (!tv->ReplaceHandler(false))
824 CEvent::Sleep(5);
825 }
826
827 // get the configuration from the client
828 m_libcec->AddLog(CEC_LOG_NOTICE, "registering new CEC client - v%s", ToString((cec_client_version)configuration.clientVersion));
829
830 // get the current ackmask, so we can restore it if polling fails
831 cec_logical_addresses previousMask = GetLogicalAddresses();
832
833 // mark as uninitialised
834 client->SetInitialised(false);
835
836 // find logical addresses for this client
837 if (!AllocateLogicalAddresses(client))
838 {
839 m_libcec->AddLog(CEC_LOG_ERROR, "failed to register the new CEC client - cannot allocate the requested device types");
840 SetLogicalAddresses(previousMask);
841 return false;
842 }
843
844 // get the settings from the rom
845 if (configuration.bGetSettingsFromROM == 1)
846 {
847 libcec_configuration config; config.Clear();
848 m_communication->GetConfiguration(config);
849
850 CLockObject lock(m_mutex);
851 if (!config.deviceTypes.IsEmpty())
852 configuration.deviceTypes = config.deviceTypes;
853 if (CLibCEC::IsValidPhysicalAddress(config.iPhysicalAddress))
854 configuration.iPhysicalAddress = config.iPhysicalAddress;
855 snprintf(configuration.strDeviceName, 13, "%s", config.strDeviceName);
856 }
857
858 // set the firmware version and build date
859 configuration.serverVersion = LIBCEC_VERSION_CURRENT;
860 configuration.iFirmwareVersion = m_communication->GetFirmwareVersion();
861 configuration.iFirmwareBuildDate = m_communication->GetFirmwareBuildDate();
862 configuration.adapterType = m_communication->GetAdapterType();
863
864 // mark the client as registered
865 client->SetRegistered(true);
866
867 sourceAddress = client->GetPrimaryLogicalAdddress();
868
869 // initialise the client
870 bool bReturn = client->OnRegister();
871
872 // log the new registration
873 CStdString strLog;
874 strLog.Format("%s: %s", bReturn ? "CEC client registered" : "failed to register the CEC client", client->GetConnectionInfo().c_str());
875 m_libcec->AddLog(bReturn ? CEC_LOG_NOTICE : CEC_LOG_ERROR, strLog);
876
877 // display a warning if the firmware can be upgraded
878 if (bReturn && !IsRunningLatestFirmware())
879 {
880 const char *strUpgradeMessage = "The firmware of this adapter can be upgraded. Please visit http://blog.pulse-eight.com/ for more information.";
881 m_libcec->AddLog(CEC_LOG_WARNING, strUpgradeMessage);
882 libcec_parameter param;
883 param.paramData = (void*)strUpgradeMessage; param.paramType = CEC_PARAMETER_TYPE_STRING;
884 client->Alert(CEC_ALERT_SERVICE_DEVICE, param);
885 }
886
887 // ensure that the command handler for the TV is initialised
888 if (bReturn)
889 {
890 CCECCommandHandler *handler = GetTV()->GetHandler();
891 if (handler)
892 handler->InitHandler();
893 GetTV()->MarkHandlerReady();
894 }
895
896 // report our OSD name to the TV, since some TVs don't request it
897 client->GetPrimaryDevice()->TransmitOSDName(CECDEVICE_TV, false);
898
899 // request the power status of the TV
900 tv->RequestPowerStatus(sourceAddress, true, true);
901
902 return bReturn;
903}
904
905bool CCECProcessor::UnregisterClient(CCECClient *client)
906{
907 if (!client)
908 return false;
909
910 if (client->IsRegistered())
911 m_libcec->AddLog(CEC_LOG_NOTICE, "unregistering client: %s", client->GetConnectionInfo().c_str());
912
913 // notify the client that it will be unregistered
914 client->OnUnregister();
915
916 {
917 CLockObject lock(m_mutex);
918 // find all devices that match the LA's of this client
919 CECDEVICEVEC devices;
920 m_busDevices->GetByLogicalAddresses(devices, client->GetConfiguration()->logicalAddresses);
921 for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
922 {
923 // find the client
924 map<cec_logical_address, CCECClient *>::iterator entry = m_clients.find((*it)->GetLogicalAddress());
925 // unregister the client
926 if (entry != m_clients.end())
927 m_clients.erase(entry);
928
929 // reset the device status
930 (*it)->ResetDeviceStatus(true);
931 }
932 }
933
934 // set the new ackmask
935 cec_logical_addresses addresses = GetLogicalAddresses();
936 if (SetLogicalAddresses(addresses))
937 {
938 // no more clients left, disable controlled mode
939 if (addresses.IsEmpty() && !m_bMonitor)
940 m_communication->SetControlledMode(false);
941
942 return true;
943 }
944
945 return false;
946}
947
948void CCECProcessor::UnregisterClients(void)
949{
950 m_libcec->AddLog(CEC_LOG_DEBUG, "unregistering all CEC clients");
951
952 vector<CCECClient *> clients = m_libcec->GetClients();
953 for (vector<CCECClient *>::iterator client = clients.begin(); client != clients.end(); client++)
954 UnregisterClient(*client);
955
956 CLockObject lock(m_mutex);
957 m_clients.clear();
958}
959
960CCECClient *CCECProcessor::GetClient(const cec_logical_address address)
961{
962 CLockObject lock(m_mutex);
963 map<cec_logical_address, CCECClient *>::const_iterator client = m_clients.find(address);
964 if (client != m_clients.end())
965 return client->second;
966 return NULL;
967}
968
969CCECClient *CCECProcessor::GetPrimaryClient(void)
970{
971 CLockObject lock(m_mutex);
972 map<cec_logical_address, CCECClient *>::const_iterator client = m_clients.begin();
973 if (client != m_clients.end())
974 return client->second;
975 return NULL;
976}
977
978CCECBusDevice *CCECProcessor::GetPrimaryDevice(void)
979{
980 return m_busDevices->At(GetLogicalAddress());
981}
982
983cec_logical_address CCECProcessor::GetLogicalAddress(void)
984{
985 cec_logical_addresses addresses = GetLogicalAddresses();
986 return addresses.primary;
987}
988
989cec_logical_addresses CCECProcessor::GetLogicalAddresses(void)
990{
991 CLockObject lock(m_mutex);
992 cec_logical_addresses addresses;
993 addresses.Clear();
994 for (map<cec_logical_address, CCECClient *>::const_iterator client = m_clients.begin(); client != m_clients.end(); client++)
995 addresses.Set(client->first);
996
997 return addresses;
998}
999
1000bool CCECProcessor::IsHandledByLibCEC(const cec_logical_address address) const
1001{
1002 CCECBusDevice *device = GetDevice(address);
1003 return device && device->IsHandledByLibCEC();
1004}
1005
1006bool CCECProcessor::IsRunningLatestFirmware(void)
1007{
1008 return m_communication && m_communication->IsOpen() ?
1009 m_communication->IsRunningLatestFirmware() :
1010 true;
1011}
1012
1013void CCECProcessor::SwitchMonitoring(bool bSwitchTo)
1014{
1015 {
1016 CLockObject lock(m_mutex);
1017 m_bMonitor = bSwitchTo;
1018 }
1019 if (bSwitchTo)
1020 UnregisterClients();
1021}
1022
1023void CCECProcessor::HandleLogicalAddressLost(cec_logical_address oldAddress)
1024{
1025 // stall outgoing messages until we know our new LA
1026 m_bStallCommunication = true;
1027
1028 m_libcec->AddLog(CEC_LOG_NOTICE, "logical address %x was taken by another device, allocating a new address", oldAddress);
1029 CCECClient* client = GetClient(oldAddress);
1030 if (!client)
1031 client = GetPrimaryClient();
1032 if (client)
1033 {
1034 if (m_addrAllocator)
1035 while (m_addrAllocator->IsRunning()) Sleep(5);
1036 delete m_addrAllocator;
1037
1038 m_addrAllocator = new CCECAllocateLogicalAddress(this, client);
1039 m_addrAllocator->CreateThread();
1040 }
1041}
1042
1043void CCECProcessor::HandlePhysicalAddressChanged(uint16_t iNewAddress)
1044{
1045 m_libcec->AddLog(CEC_LOG_NOTICE, "physical address changed to %04x", iNewAddress);
1046 CCECClient* client = GetPrimaryClient();
1047 if (client)
1048 client->SetPhysicalAddress(iNewAddress);
1049}
1050
1051uint16_t CCECProcessor::GetAdapterVendorId(void) const
1052{
1053 return m_communication ? m_communication->GetAdapterVendorId() : 0;
1054}
1055
1056uint16_t CCECProcessor::GetAdapterProductId(void) const
1057{
1058 return m_communication ? m_communication->GetAdapterProductId() : 0;
1059}
1060
1061CCECAllocateLogicalAddress::CCECAllocateLogicalAddress(CCECProcessor* processor, CCECClient* client) :
1062 m_processor(processor),
1063 m_client(client) { }
1064
1065void* CCECAllocateLogicalAddress::Process(void)
1066{
1067 m_processor->AllocateLogicalAddresses(m_client);
1068 return NULL;
1069}