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