1 /*
2  * This file is part of the libCEC(R) library.
3  *
4  * libCEC(R) is Copyright (C) 2011-2015 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., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301  USA
23  *
24  *
25  * Alternatively, you can license this library under a commercial license,
26  * please contact Pulse-Eight Licensing for more information.
27  *
28  * For more information contact:
29  * Pulse-Eight Licensing       <license@pulse-eight.com>
30  *     http://www.pulse-eight.com/
31  *     http://www.pulse-eight.net/
32  */
33 
34 #include "env.h"
35 #include "LibCEC.h"
36 
37 #include "adapter/AdapterFactory.h"
38 #include "adapter/AdapterCommunication.h"
39 #include "CECProcessor.h"
40 #include "devices/CECAudioSystem.h"
41 #include "devices/CECBusDevice.h"
42 #include "devices/CECPlaybackDevice.h"
43 #include "devices/CECTV.h"
44 #include "p8-platform/util/timeutils.h"
45 #include "p8-platform/util/util.h"
46 #include <stdio.h>
47 #include <stdlib.h>
48 
49 #include "CECClient.h"
50 
51 using namespace CEC;
52 using namespace P8PLATFORM;
53 
CLibCEC(void)54 CLibCEC::CLibCEC(void) :
55     m_iStartTime(GetTimeMs()),
56     m_client(nullptr)
57 {
58   m_cec = new CCECProcessor(this);
59 }
60 
~CLibCEC(void)61 CLibCEC::~CLibCEC(void)
62 {
63   // unregister all clients
64   if (m_cec && m_cec->IsRunning())
65     m_cec->UnregisterClients();
66 
67   m_clients.clear();
68 
69   // delete the adapter connection
70   SAFE_DELETE(m_cec);
71 
72   // delete active client
73   m_client.reset();
74 }
75 
Open(const char * strPort,uint32_t iTimeoutMs)76 bool CLibCEC::Open(const char *strPort, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
77 {
78   if (!m_cec || !strPort)
79     return false;
80 
81   // open a new connection
82   if (!m_cec->Start(strPort, CEC_SERIAL_DEFAULT_BAUDRATE, iTimeoutMs))
83   {
84     AddLog(CEC_LOG_ERROR, "could not start CEC communications");
85     return false;
86   }
87 
88   // register all clients
89   for (std::vector<CECClientPtr>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
90   {
91     if (!m_cec->RegisterClient(*it))
92     {
93       AddLog(CEC_LOG_ERROR, "failed to register a CEC client");
94       return false;
95     }
96   }
97 
98   return true;
99 }
100 
Close(void)101 void CLibCEC::Close(void)
102 {
103   if (!m_cec)
104     return;
105 
106   // unregister all clients
107   m_cec->UnregisterClients();
108 
109   // close the connection
110   m_cec->Close();
111 }
112 
FindAdapters(cec_adapter * deviceList,uint8_t iBufSize,const char * strDevicePath)113 int8_t CLibCEC::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = nullptr */)
114 {
115   return CAdapterFactory(this).FindAdapters(deviceList, iBufSize, strDevicePath);
116 }
117 
StartBootloader(void)118 bool CLibCEC::StartBootloader(void)
119 {
120   return m_cec ? m_cec->StartBootloader() : false;
121 }
122 
PingAdapter(void)123 bool CLibCEC::PingAdapter(void)
124 {
125   return m_client ? m_client->PingAdapter() : false;
126 }
127 
128 #if CEC_LIB_VERSION_MAJOR >= 5
SetCallbacks(ICECCallbacks * callbacks,void * cbParam)129 bool CLibCEC::SetCallbacks(ICECCallbacks *callbacks, void *cbParam)
130 {
131   return !!m_client ? m_client->EnableCallbacks(cbParam, callbacks) : false;
132 }
133 
DisableCallbacks(void)134 bool CLibCEC::DisableCallbacks(void)
135 {
136   return !!m_client ? m_client->EnableCallbacks(nullptr, nullptr) : false;
137 }
138 
EnableCallbacks(void * cbParam,ICECCallbacks * callbacks)139 bool CLibCEC::EnableCallbacks(void *cbParam, ICECCallbacks *callbacks)
140 {
141   return SetCallbacks(callbacks, cbParam);
142 }
143 #else
EnableCallbacks(void * cbParam,ICECCallbacks * callbacks)144 bool CLibCEC::EnableCallbacks(void *cbParam, ICECCallbacks *callbacks)
145 {
146   return !!m_client ? m_client->EnableCallbacks(cbParam, callbacks) : false;
147 }
148 #endif
149 
GetCurrentConfiguration(libcec_configuration * configuration)150 bool CLibCEC::GetCurrentConfiguration(libcec_configuration *configuration)
151 {
152   return m_client ? m_client->GetCurrentConfiguration(*configuration) : false;
153 }
154 
SetConfiguration(const libcec_configuration * configuration)155 bool CLibCEC::SetConfiguration(const libcec_configuration *configuration)
156 {
157   return m_client ? m_client->SetConfiguration(*configuration) : false;
158 }
159 
160 #if CEC_LIB_VERSION_MAJOR >= 5
CanSaveConfiguration(void)161 bool CLibCEC::CanSaveConfiguration(void)
162 #else
163 bool CLibCEC::CanPersistConfiguration(void)
164 #endif
165 {
166   return m_client ? m_client->CanSaveConfiguration() : false;
167 }
168 
169 #if CEC_LIB_VERSION_MAJOR < 5
PersistConfiguration(libcec_configuration * configuration)170 bool CLibCEC::PersistConfiguration(libcec_configuration *configuration)
171 {
172   return SetConfiguration(configuration);
173 }
174 #endif
175 
RescanActiveDevices(void)176 void CLibCEC::RescanActiveDevices(void)
177 {
178   if (m_client)
179     m_client->RescanActiveDevices();
180 }
181 
IsLibCECActiveSource(void)182 bool CLibCEC::IsLibCECActiveSource(void)
183 {
184   return m_client ? m_client->IsLibCECActiveSource() : false;
185 }
186 
Transmit(const cec_command & data)187 bool CLibCEC::Transmit(const cec_command &data)
188 {
189   return m_client ? m_client->Transmit(data, false) : false;
190 }
191 
SetLogicalAddress(cec_logical_address iLogicalAddress)192 bool CLibCEC::SetLogicalAddress(cec_logical_address iLogicalAddress)
193 {
194   return m_client ? m_client->SetLogicalAddress(iLogicalAddress) : false;
195 }
196 
SetPhysicalAddress(uint16_t iPhysicalAddress)197 bool CLibCEC::SetPhysicalAddress(uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS */)
198 {
199   return m_client ? m_client->SetPhysicalAddress(iPhysicalAddress) : false;
200 }
201 
SetHDMIPort(cec_logical_address iBaseDevice,uint8_t iPort)202 bool CLibCEC::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort /* = CEC_DEFAULT_HDMI_PORT */)
203 {
204   return m_client ? m_client->SetHDMIPort(iBaseDevice, iPort) : false;
205 }
206 
PowerOnDevices(cec_logical_address address)207 bool CLibCEC::PowerOnDevices(cec_logical_address address /* = CECDEVICE_TV */)
208 {
209   return m_client ? m_client->SendPowerOnDevices(address) : false;
210 }
211 
StandbyDevices(cec_logical_address address)212 bool CLibCEC::StandbyDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
213 {
214   return m_client ? m_client->SendStandbyDevices(address) : false;
215 }
216 
SetActiveSource(cec_device_type type)217 bool CLibCEC::SetActiveSource(cec_device_type type /* = CEC_DEVICE_TYPE_RESERVED */)
218 {
219   return m_client ? m_client->SendSetActiveSource(type) : false;
220 }
221 
SetDeckControlMode(cec_deck_control_mode mode,bool bSendUpdate)222 bool CLibCEC::SetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate /* = true */)
223 {
224   return m_client ? m_client->SendSetDeckControlMode(mode, bSendUpdate) : false;
225 }
226 
SetDeckInfo(cec_deck_info info,bool bSendUpdate)227 bool CLibCEC::SetDeckInfo(cec_deck_info info, bool bSendUpdate /* = true */)
228 {
229   return m_client ? m_client->SendSetDeckInfo(info, bSendUpdate) : false;
230 }
231 
SetInactiveView(void)232 bool CLibCEC::SetInactiveView(void)
233 {
234   return m_client ? m_client->SendSetInactiveView() : false;
235 }
236 
SetMenuState(cec_menu_state state,bool bSendUpdate)237 bool CLibCEC::SetMenuState(cec_menu_state state, bool bSendUpdate /* = true */)
238 {
239   return m_client ? m_client->SendSetMenuState(state, bSendUpdate) : false;
240 }
241 
SetOSDString(cec_logical_address iLogicalAddress,cec_display_control duration,const char * strMessage)242 bool CLibCEC::SetOSDString(cec_logical_address iLogicalAddress, cec_display_control duration, const char *strMessage)
243 {
244   return m_client ? m_client->SendSetOSDString(iLogicalAddress, duration, strMessage) : false;
245 }
246 
SwitchMonitoring(bool bEnable)247 bool CLibCEC::SwitchMonitoring(bool bEnable)
248 {
249   return m_client ? m_client->SwitchMonitoring(bEnable) : false;
250 }
251 
GetDeviceCecVersion(cec_logical_address iAddress)252 cec_version CLibCEC::GetDeviceCecVersion(cec_logical_address iAddress)
253 {
254   return m_client ? m_client->GetDeviceCecVersion(iAddress) : CEC_VERSION_UNKNOWN;
255 }
256 
GetDeviceMenuLanguage(cec_logical_address iAddress)257 std::string CLibCEC::GetDeviceMenuLanguage(cec_logical_address iAddress)
258 {
259   return !!m_client ? m_client->GetDeviceMenuLanguage(iAddress) : "???";
260 }
261 
GetDeviceVendorId(cec_logical_address iAddress)262 uint32_t CLibCEC::GetDeviceVendorId(cec_logical_address iAddress)
263 {
264   return m_client ? m_client->GetDeviceVendorId(iAddress) : (uint32_t)CEC_VENDOR_UNKNOWN;
265 }
266 
GetDevicePhysicalAddress(cec_logical_address iAddress)267 uint16_t CLibCEC::GetDevicePhysicalAddress(cec_logical_address iAddress)
268 {
269   return m_client ? m_client->GetDevicePhysicalAddress(iAddress) : CEC_INVALID_PHYSICAL_ADDRESS;
270 }
271 
GetDevicePowerStatus(cec_logical_address iAddress)272 cec_power_status CLibCEC::GetDevicePowerStatus(cec_logical_address iAddress)
273 {
274   return m_client ? m_client->GetDevicePowerStatus(iAddress) : CEC_POWER_STATUS_UNKNOWN;
275 }
276 
PollDevice(cec_logical_address iAddress)277 bool CLibCEC::PollDevice(cec_logical_address iAddress)
278 {
279   return m_client ? m_client->PollDevice(iAddress) : false;
280 }
281 
GetActiveDevices(void)282 cec_logical_addresses CLibCEC::GetActiveDevices(void)
283 {
284   cec_logical_addresses addresses;
285   addresses.Clear();
286   if (m_client)
287     addresses = m_client->GetActiveDevices();
288   return addresses;
289 }
290 
IsActiveDevice(cec_logical_address iAddress)291 bool CLibCEC::IsActiveDevice(cec_logical_address iAddress)
292 {
293   return m_client ? m_client->IsActiveDevice(iAddress) : false;
294 }
295 
IsActiveDeviceType(cec_device_type type)296 bool CLibCEC::IsActiveDeviceType(cec_device_type type)
297 {
298   return m_client ? m_client->IsActiveDeviceType(type) : false;
299 }
300 
VolumeUp(bool bSendRelease)301 uint8_t CLibCEC::VolumeUp(bool bSendRelease /* = true */)
302 {
303   return m_client ? m_client->SendVolumeUp(bSendRelease) : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
304 }
305 
VolumeDown(bool bSendRelease)306 uint8_t CLibCEC::VolumeDown(bool bSendRelease /* = true */)
307 {
308   return m_client ? m_client->SendVolumeDown(bSendRelease) : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
309 }
310 
311 #if CEC_LIB_VERSION_MAJOR >= 5
MuteAudio(void)312 uint8_t CLibCEC::MuteAudio(void)
313 {
314   return !!m_client ?
315     m_client->SendMuteAudio() :
316     (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
317 }
318 #endif
319 
SendKeypress(cec_logical_address iDestination,cec_user_control_code key,bool bWait)320 bool CLibCEC::SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */)
321 {
322   return m_client ? m_client->SendKeypress(iDestination, key, bWait) : false;
323 }
324 
SendKeyRelease(cec_logical_address iDestination,bool bWait)325 bool CLibCEC::SendKeyRelease(cec_logical_address iDestination, bool bWait /* = true */)
326 {
327   return m_client ? m_client->SendKeyRelease(iDestination, bWait) : false;
328 }
329 
GetDeviceOSDName(cec_logical_address iAddress)330 std::string CLibCEC::GetDeviceOSDName(cec_logical_address iAddress)
331 {
332   return !!m_client ?
333       m_client->GetDeviceOSDName(iAddress) :
334       "";
335 }
336 
GetActiveSource(void)337 cec_logical_address CLibCEC::GetActiveSource(void)
338 {
339   return m_client ? m_client->GetActiveSource() : CECDEVICE_UNKNOWN;
340 }
341 
IsActiveSource(cec_logical_address iAddress)342 bool CLibCEC::IsActiveSource(cec_logical_address iAddress)
343 {
344   return m_client ? m_client->IsActiveSource(iAddress) : false;
345 }
SetStreamPath(cec_logical_address iAddress)346 bool CLibCEC::SetStreamPath(cec_logical_address iAddress)
347 {
348   return m_client ? m_client->SetStreamPath(iAddress) : false;
349 }
350 
SetStreamPath(uint16_t iPhysicalAddress)351 bool CLibCEC::SetStreamPath(uint16_t iPhysicalAddress)
352 {
353   return m_client ? m_client->SetStreamPath(iPhysicalAddress) : false;
354 }
355 
GetLogicalAddresses(void)356 cec_logical_addresses CLibCEC::GetLogicalAddresses(void)
357 {
358   cec_logical_addresses addresses;
359   addresses.Clear();
360   if (m_client)
361     addresses = m_client->GetLogicalAddresses();
362   return addresses;
363 }
364 
GetType(cec_logical_address address)365 cec_device_type CLibCEC::GetType(cec_logical_address address)
366 {
367   return CCECTypeUtils::GetType(address);
368 }
369 
GetMaskForType(cec_logical_address address)370 uint16_t CLibCEC::GetMaskForType(cec_logical_address address)
371 {
372   return CCECTypeUtils::GetMaskForType(address);
373 }
374 
GetMaskForType(cec_device_type type)375 uint16_t CLibCEC::GetMaskForType(cec_device_type type)
376 {
377   return CCECTypeUtils::GetMaskForType(type);
378 }
379 
IsValidPhysicalAddress(uint16_t iPhysicalAddress)380 bool CLibCEC::IsValidPhysicalAddress(uint16_t iPhysicalAddress)
381 {
382   return iPhysicalAddress >= CEC_MIN_PHYSICAL_ADDRESS &&
383          iPhysicalAddress <= CEC_MAX_PHYSICAL_ADDRESS;
384 }
385 
CheckKeypressTimeout(void)386 uint16_t CLibCEC::CheckKeypressTimeout(void)
387 {
388   uint16_t timeout = CEC_PROCESSOR_SIGNAL_WAIT_TIME;
389   // check all clients
390   for (std::vector<CECClientPtr>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
391   {
392     uint16_t t = (*it)->CheckKeypressTimeout();
393     if (t < timeout)
394       timeout = t;
395   }
396   return timeout;
397 }
398 
AddLog(const cec_log_level level,const char * strFormat,...)399 void CLibCEC::AddLog(const cec_log_level level, const char *strFormat, ...)
400 {
401   // format the message
402   va_list argList;
403   cec_log_message_cpp message;
404   message.level = level;
405   message.time = GetTimeMs() - m_iStartTime;
406   va_start(argList, strFormat);
407   message.message = StringUtils::FormatV(strFormat, argList);
408   va_end(argList);
409 
410   // send the message to all clients
411   CLockObject lock(m_mutex);
412   for (std::vector<CECClientPtr>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
413     (*it)->AddLog(message);
414 }
415 
AddCommand(const cec_command & command)416 void CLibCEC::AddCommand(const cec_command &command)
417 {
418   // send the command to all clients
419   CLockObject lock(m_mutex);
420   for (std::vector<CECClientPtr>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
421     (*it)->QueueAddCommand(command);
422 }
423 
Alert(const libcec_alert type,const libcec_parameter & param)424 void CLibCEC::Alert(const libcec_alert type, const libcec_parameter &param)
425 {
426   // send the alert to all clients
427   CLockObject lock(m_mutex);
428   for (std::vector<CECClientPtr>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
429     (*it)->Alert(type, param);
430 }
431 
RegisterClient(libcec_configuration & configuration)432 CECClientPtr CLibCEC::RegisterClient(libcec_configuration &configuration)
433 {
434   if (!m_cec)
435     return CECClientPtr();
436   if (configuration.clientVersion < LIBCEC_VERSION_TO_UINT(4, 0, 0))
437   {
438     AddLog(CEC_LOG_ERROR, "failed to register a new CEC client: client version %s is no longer supported", CCECTypeUtils::VersionToString(configuration.clientVersion).c_str());
439     return CECClientPtr();
440   }
441 
442   // create a new client instance
443   CECClientPtr newClient = CECClientPtr(new CCECClient(m_cec, configuration));
444   if (!newClient)
445     return newClient;
446   m_clients.push_back(newClient);
447 
448   // if the default client isn't set, set it
449   if (!m_client)
450     m_client = newClient;
451 
452   // register the new client
453   if (m_cec->CECInitialised())
454   {
455     if (!m_cec->RegisterClient(newClient))
456       newClient = CECClientPtr();
457     else
458     {
459       // update the current configuration
460       newClient->GetCurrentConfiguration(configuration);
461     }
462   }
463 
464   return newClient;
465 }
466 
CECInitialise(libcec_configuration * configuration)467 ICECAdapter* CECInitialise(libcec_configuration *configuration)
468 {
469   if (!configuration)
470     return nullptr;
471 
472   // create a new libCEC instance
473   CLibCEC *lib = new CLibCEC;
474 
475   // register a new client
476   CECClientPtr client;
477   return (!!lib && !!lib->RegisterClient(*configuration)) ?
478     static_cast<ICECAdapter*> (lib) :
479     nullptr;
480 }
481 
CECStartBootloader(void)482 bool CECStartBootloader(void)
483 {
484   bool bReturn(false);
485   cec_adapter deviceList[1];
486   if (CAdapterFactory(nullptr).FindAdapters(deviceList, 1, 0) > 0)
487   {
488     CAdapterFactory factory(nullptr);
489     IAdapterCommunication *comm = factory.GetInstance(deviceList[0].comm);
490     if (comm)
491     {
492       CTimeout timeout(CEC_DEFAULT_CONNECT_TIMEOUT);
493       while (timeout.TimeLeft() > 0 &&
494           (bReturn = comm->Open(timeout.TimeLeft() / CEC_CONNECT_TRIES, true)) == false)
495       {
496         comm->Close();
497         CEvent::Sleep(500);
498       }
499       if (comm->IsOpen())
500         bReturn = comm->StartBootloader();
501 
502       delete comm;
503     }
504   }
505 
506   return bReturn;
507 }
508 
CECDestroy(CEC::ICECAdapter * instance)509 void CECDestroy(CEC::ICECAdapter *instance)
510 {
511   SAFE_DELETE(instance);
512 }
513 
GetDeviceInformation(const char * strPort,libcec_configuration * config,uint32_t iTimeoutMs)514 bool CLibCEC::GetDeviceInformation(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
515 {
516   if (m_cec->IsRunning())
517     return false;
518 
519   return m_cec->GetDeviceInformation(strPort, config, iTimeoutMs);
520 }
521 
GetLibInfo(void)522 const char *CLibCEC::GetLibInfo(void)
523 {
524 #ifndef LIB_INFO
525 #ifdef _WIN32
526 #define FEATURES "'P8 USB' 'P8 USB detect'"
527 #ifdef _WIN64
528 #define HOST_TYPE "Windows (x64)"
529 #else
530 #define HOST_TYPE "Windows (x86)"
531 #endif
532 #else
533 #define HOST_TYPE "unknown"
534 #define FEATURES "unknown"
535 #endif
536 
537   return "host: " HOST_TYPE ", features: " FEATURES ", compiled: " __DATE__;
538 #else
539   return LIB_INFO;
540 #endif
541 }
542 
InitVideoStandalone(void)543 void CLibCEC::InitVideoStandalone(void)
544 {
545   CAdapterFactory::InitVideoStandalone();
546 }
GetAdapterVendorId(void) const547 uint16_t CLibCEC::GetAdapterVendorId(void) const
548 {
549   return m_cec && m_cec->IsRunning() ? m_cec->GetAdapterVendorId() : 0;
550 }
551 
GetAdapterProductId(void) const552 uint16_t CLibCEC::GetAdapterProductId(void) const
553 {
554   return m_cec && m_cec->IsRunning() ? m_cec->GetAdapterProductId() : 0;
555 }
556 
AudioToggleMute(void)557 uint8_t CLibCEC::AudioToggleMute(void)
558 {
559   return m_client ? m_client->AudioToggleMute() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
560 }
561 
AudioMute(void)562 uint8_t CLibCEC::AudioMute(void)
563 {
564   return m_client ? m_client->AudioMute() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
565 }
566 
AudioUnmute(void)567 uint8_t CLibCEC::AudioUnmute(void)
568 {
569   return m_client ? m_client->AudioUnmute() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
570 }
571 
AudioStatus(void)572 uint8_t CLibCEC::AudioStatus(void)
573 {
574   return m_client ? m_client->AudioStatus() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
575 }
576 
DetectAdapters(cec_adapter_descriptor * deviceList,uint8_t iBufSize,const char * strDevicePath,bool bQuickScan)577 int8_t CLibCEC::DetectAdapters(cec_adapter_descriptor *deviceList, uint8_t iBufSize, const char *strDevicePath /* = nullptr */, bool bQuickScan /* = false */)
578 {
579   int8_t iAdaptersFound = CAdapterFactory(this).DetectAdapters(deviceList, iBufSize, strDevicePath);
580   if (!bQuickScan)
581   {
582     for (int8_t iPtr = 0; iPtr < iAdaptersFound; iPtr++)
583     {
584       libcec_configuration config;
585       GetDeviceInformation(deviceList[iPtr].strComName, &config);
586       deviceList[iPtr].iFirmwareVersion   = config.iFirmwareVersion;
587       deviceList[iPtr].iPhysicalAddress   = config.iPhysicalAddress;
588       deviceList[iPtr].iFirmwareBuildDate = config.iFirmwareBuildDate;
589       deviceList[iPtr].adapterType        = config.adapterType;
590     }
591   }
592   return iAdaptersFound;
593 }
594 
HexStrToInt(const std::string & data,uint8_t & value)595 inline bool HexStrToInt(const std::string& data, uint8_t& value)
596 {
597   int iTmp(0);
598   if (sscanf(data.c_str(), "%x", &iTmp) == 1)
599   {
600     if (iTmp > 256)
601       value = 255;
602     else if (iTmp < 0)
603       value = 0;
604     else
605       value = (uint8_t) iTmp;
606 
607     return true;
608   }
609 
610   return false;
611 }
612 
CommandFromString(const char * strCommand)613 cec_command CLibCEC::CommandFromString(const char* strCommand)
614 {
615   std::vector<std::string> splitCommand = StringUtils::Split(strCommand, ":");
616   cec_command retval;
617   unsigned long tmpVal;
618 
619   for (std::vector<std::string>::const_iterator it = splitCommand.begin(); it != splitCommand.end(); ++it)
620   {
621     tmpVal = strtoul((*it).c_str(), nullptr, 16);
622     if (tmpVal <= 0xFF)
623       retval.PushBack((uint8_t)tmpVal);
624   }
625 
626   return retval;
627 }
628 
PrintVersion(uint32_t version,char * buf,size_t bufSize)629 void CLibCEC::PrintVersion(uint32_t version, char* buf, size_t bufSize)
630 {
631   std::string strVersion = CCECTypeUtils::VersionToString(version);
632   snprintf(buf, bufSize, "%s", strVersion.c_str());
633 }
634 
AudioEnable(bool enable)635 bool CLibCEC::AudioEnable(bool enable)
636 {
637   return !!m_client ?
638       m_client->AudioEnable(enable) :
639       false;
640 }
641 
642 #if CEC_LIB_VERSION_MAJOR >= 5
GetStats(struct cec_adapter_stats * stats)643 bool CLibCEC::GetStats(struct cec_adapter_stats* stats)
644 {
645   return !!m_client ?
646       m_client->GetStats(stats) :
647       false;
648 }
649 #endif
650