cec-config: fixed typo
[deb_libcec.git] / src / lib / LibCEC.cpp
CommitLineData
2abe74eb
LOK
1/*
2 * This file is part of the libCEC(R) library.
3 *
b492c10e 4 * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
2abe74eb
LOK
5 * libCEC(R) is an original work, containing original code.
6 *
7 * libCEC(R) is a trademark of Pulse-Eight Limited.
8 *
9 * This program is dual-licensed; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 *
23 *
24 * Alternatively, you can license this library under a commercial license,
25 * please contact Pulse-Eight Licensing for more information.
26 *
27 * For more information contact:
28 * Pulse-Eight Licensing <license@pulse-eight.com>
29 * http://www.pulse-eight.com/
30 * http://www.pulse-eight.net/
31 */
32
33#include "LibCEC.h"
34
7bb4ed43 35#include "adapter/USBCECAdapterDetection.h"
2abe74eb 36#include "CECProcessor.h"
0f23c85c 37#include "devices/CECBusDevice.h"
ba65909d
LOK
38#include "platform/util/timeutils.h"
39#include "platform/util/StdString.h"
2abe74eb
LOK
40
41using namespace std;
42using namespace CEC;
f00ff009 43using namespace PLATFORM;
2abe74eb 44
4f362964 45CLibCEC::CLibCEC(const char *strDeviceName, cec_device_type_list types, uint16_t iPhysicalAddress /* = 0 */) :
f8513317
LOK
46 m_iStartTime(GetTimeMs()),
47 m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
fa4798bd 48 m_buttontime(0),
547b390d
LOK
49 m_callbacks(NULL),
50 m_cbParam(NULL)
f8513317 51{
4f362964 52 m_cec = new CCECProcessor(this, strDeviceName, types, iPhysicalAddress);
f8513317
LOK
53}
54
2abe74eb
LOK
55CLibCEC::~CLibCEC(void)
56{
12027dbe 57 Close();
2abe74eb 58 delete m_cec;
2abe74eb
LOK
59}
60
25701fa6 61bool CLibCEC::Open(const char *strPort, uint32_t iTimeoutMs /* = 10000 */)
2abe74eb 62{
1113cb7d 63 if (m_cec->IsRunning())
2abe74eb
LOK
64 {
65 AddLog(CEC_LOG_ERROR, "connection already open");
66 return false;
67 }
68
1113cb7d 69 if (!m_cec->Start(strPort, 38400, iTimeoutMs))
2abe74eb
LOK
70 {
71 AddLog(CEC_LOG_ERROR, "could not start CEC communications");
72 return false;
73 }
74
75 return true;
76}
77
78void CLibCEC::Close(void)
79{
25701fa6 80 if (m_cec)
eca71746 81 m_cec->Close();
2abe74eb
LOK
82}
83
547b390d 84bool CLibCEC::EnableCallbacks(void *cbParam, ICECCallbacks *callbacks)
fa4798bd 85{
f00ff009 86 CLockObject lock(m_mutex);
fa4798bd 87 if (m_cec)
547b390d
LOK
88 {
89 m_cbParam = cbParam;
fa4798bd 90 m_callbacks = callbacks;
547b390d 91 }
fa4798bd
LOK
92 return false;
93}
94
25701fa6 95int8_t CLibCEC::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */)
2abe74eb
LOK
96{
97 CStdString strDebug;
98 if (strDevicePath)
99 strDebug.Format("trying to autodetect the com port for device path '%s'", strDevicePath);
100 else
101 strDebug.Format("trying to autodetect all CEC adapters");
102 AddLog(CEC_LOG_DEBUG, strDebug);
103
7bb4ed43 104 return CUSBCECAdapterDetection::FindAdapters(deviceList, iBufSize, strDevicePath);
2abe74eb
LOK
105}
106
107bool CLibCEC::PingAdapter(void)
108{
1113cb7d 109 return m_cec ? m_cec->PingAdapter() : false;
2abe74eb
LOK
110}
111
112bool CLibCEC::StartBootloader(void)
113{
1113cb7d 114 return m_cec ? m_cec->StartBootloader() : false;
2abe74eb
LOK
115}
116
2abe74eb
LOK
117bool CLibCEC::GetNextLogMessage(cec_log_message *message)
118{
25701fa6 119 return (m_logBuffer.Pop(*message));
2abe74eb
LOK
120}
121
122bool CLibCEC::GetNextKeypress(cec_keypress *key)
123{
124 return m_keyBuffer.Pop(*key);
125}
126
127bool CLibCEC::GetNextCommand(cec_command *command)
128{
129 return m_commandBuffer.Pop(*command);
130}
131
8d84e2c0 132bool CLibCEC::Transmit(const cec_command &data)
2abe74eb 133{
8d84e2c0 134 return m_cec ? m_cec->Transmit(data) : false;
2abe74eb
LOK
135}
136
137bool CLibCEC::SetLogicalAddress(cec_logical_address iLogicalAddress)
138{
139 return m_cec ? m_cec->SetLogicalAddress(iLogicalAddress) : false;
140}
141
16b1e052 142bool CLibCEC::SetPhysicalAddress(uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS */)
2492216a
LOK
143{
144 return m_cec ? m_cec->SetPhysicalAddress(iPhysicalAddress) : false;
145}
146
d2f1c157 147bool CLibCEC::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort /* = CEC_DEFAULT_HDMI_PORT */)
16b1e052 148{
d2f1c157 149 return m_cec ? m_cec->SetHDMIPort(iBaseDevice, iPort) : false;
16b1e052
LOK
150}
151
2dbd78f8
LOK
152bool CLibCEC::EnablePhysicalAddressDetection(void)
153{
154 return m_cec ? m_cec->EnablePhysicalAddressDetection() : false;
155}
156
2abe74eb
LOK
157bool CLibCEC::PowerOnDevices(cec_logical_address address /* = CECDEVICE_TV */)
158{
0f23c85c 159 return m_cec && address >= CECDEVICE_TV && address <= CECDEVICE_BROADCAST ? m_cec->m_busDevices[(uint8_t)address]->PowerOn() : false;
2abe74eb
LOK
160}
161
162bool CLibCEC::StandbyDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
163{
0f23c85c 164 return m_cec && address >= CECDEVICE_TV && address <= CECDEVICE_BROADCAST ? m_cec->m_busDevices[(uint8_t)address]->Standby() : false;
2abe74eb
LOK
165}
166
18203d17
LOK
167bool CLibCEC::SetActiveSource(cec_device_type type /* = CEC_DEVICE_TYPE_RESERVED */)
168{
169 return m_cec ? m_cec->SetActiveSource(type) : false;
170}
171
2abe74eb
LOK
172bool CLibCEC::SetActiveView(void)
173{
174 return m_cec ? m_cec->SetActiveView() : false;
175}
176
28fa6c97 177bool CLibCEC::SetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate /* = true */)
a9232a79 178{
28fa6c97 179 return m_cec ? m_cec->SetDeckControlMode(mode, bSendUpdate) : false;
a9232a79
LOK
180}
181
28fa6c97 182bool CLibCEC::SetDeckInfo(cec_deck_info info, bool bSendUpdate /* = true */)
a9232a79 183{
28fa6c97 184 return m_cec ? m_cec->SetDeckInfo(info, bSendUpdate) : false;
a9232a79
LOK
185}
186
2abe74eb
LOK
187bool CLibCEC::SetInactiveView(void)
188{
8fb8355c 189 return m_cec ? m_cec->TransmitInactiveSource() : false;
2abe74eb
LOK
190}
191
28fa6c97
LOK
192bool CLibCEC::SetMenuState(cec_menu_state state, bool bSendUpdate /* = true */)
193{
194 return m_cec ? m_cec->SetMenuState(state, bSendUpdate) : false;
195}
196
1969b140
LOK
197bool CLibCEC::SetOSDString(cec_logical_address iLogicalAddress, cec_display_control duration, const char *strMessage)
198{
38bdb943
LOK
199 return m_cec && iLogicalAddress >= CECDEVICE_TV && iLogicalAddress <= CECDEVICE_BROADCAST ?
200 m_cec->m_busDevices[m_cec->GetLogicalAddress()]->TransmitOSDString(iLogicalAddress, duration, strMessage) :
201 false;
1969b140
LOK
202}
203
8b7e5ff6
LOK
204bool CLibCEC::SwitchMonitoring(bool bEnable)
205{
206 return m_cec ? m_cec->SwitchMonitoring(bEnable) : false;
207}
208
6a1c0009
LOK
209cec_version CLibCEC::GetDeviceCecVersion(cec_logical_address iAddress)
210{
211 if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
212 return m_cec->GetDeviceCecVersion(iAddress);
213 return CEC_VERSION_UNKNOWN;
214}
215
a3269a0a
LOK
216bool CLibCEC::GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu_language *language)
217{
218 if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
219 return m_cec->GetDeviceMenuLanguage(iAddress, language);
220 return false;
221}
222
44c74256
LOK
223uint64_t CLibCEC::GetDeviceVendorId(cec_logical_address iAddress)
224{
225 if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
226 return m_cec->GetDeviceVendorId(iAddress);
227 return 0;
228}
229
eab72c40
LOK
230uint16_t CLibCEC::GetDevicePhysicalAddress(cec_logical_address iAddress)
231{
232 if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
233 return m_cec->GetDevicePhysicalAddress(iAddress);
234 return 0;
235}
236
b4b1b49b
LOK
237cec_logical_address CLibCEC::GetActiveSource(void)
238{
239 return m_cec ? m_cec->GetActiveSource() : CECDEVICE_UNKNOWN;
240}
241
242bool CLibCEC::IsActiveSource(cec_logical_address iAddress)
243{
244 if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
245 return m_cec->IsActiveSource(iAddress);
246 return false;
247}
248
e55f3f70
LOK
249cec_power_status CLibCEC::GetDevicePowerStatus(cec_logical_address iAddress)
250{
251 if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
252 return m_cec->GetDevicePowerStatus(iAddress);
253 return CEC_POWER_STATUS_UNKNOWN;
254}
44c74256 255
57f45e6c
LOK
256bool CLibCEC::PollDevice(cec_logical_address iAddress)
257{
258 if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
259 return m_cec->PollDevice(iAddress);
260 return false;
261}
262
6d858ba4
LOK
263cec_logical_addresses CLibCEC::GetActiveDevices(void)
264{
265 cec_logical_addresses addresses;
988de7b9 266 addresses.Clear();
6d858ba4
LOK
267 if (m_cec)
268 addresses = m_cec->GetActiveDevices();
269 return addresses;
270}
271
272bool CLibCEC::IsActiveDevice(cec_logical_address iAddress)
273{
274 if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
37b0c572 275 return m_cec->IsPresentDevice(iAddress);
6d858ba4
LOK
276 return false;
277}
278
279bool CLibCEC::IsActiveDeviceType(cec_device_type type)
280{
281 if (m_cec && type >= CEC_DEVICE_TYPE_TV && type <= CEC_DEVICE_TYPE_AUDIO_SYSTEM)
37b0c572 282 return m_cec->IsPresentDeviceType(type);
6d858ba4
LOK
283 return false;
284}
285
5c73f7f7 286uint8_t CLibCEC::VolumeUp(bool bSendRelease /* = true */)
04e637f9
LOK
287{
288 if (m_cec)
5c73f7f7 289 return m_cec->VolumeUp(bSendRelease);
04e637f9
LOK
290 return 0;
291}
292
5c73f7f7 293uint8_t CLibCEC::VolumeDown(bool bSendRelease /* = true */)
04e637f9
LOK
294{
295 if (m_cec)
5c73f7f7 296 return m_cec->VolumeDown(bSendRelease);
04e637f9
LOK
297 return 0;
298}
299
300
5c73f7f7 301uint8_t CLibCEC::MuteAudio(bool bSendRelease /* = true */)
04e637f9
LOK
302{
303 if (m_cec)
5c73f7f7 304 return m_cec->MuteAudio(bSendRelease);
04e637f9
LOK
305 return 0;
306}
307
4bec9d79 308bool CLibCEC::SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */)
a33794d8
LOK
309{
310 if (m_cec)
4bec9d79 311 return m_cec->TransmitKeypress(iDestination, key, bWait);
a33794d8
LOK
312 return false;
313}
314
4bec9d79 315bool CLibCEC::SendKeyRelease(cec_logical_address iDestination, bool bWait /* = true */)
a33794d8
LOK
316{
317 if (m_cec)
4bec9d79 318 return m_cec->TransmitKeyRelease(iDestination, bWait);
a33794d8
LOK
319 return false;
320}
321
f71a1df9 322cec_osd_name CLibCEC::GetDeviceOSDName(cec_logical_address iAddress)
ed21be2a
LOK
323{
324 cec_osd_name retVal;
325 retVal.device = iAddress;
326 retVal.name[0] = 0;
327
328 if (m_cec)
329 retVal = m_cec->GetDeviceOSDName(iAddress);
330
331 return retVal;
332}
333
5477a250 334void CLibCEC::AddLog(cec_log_level level, const char *strFormat, ...)
2abe74eb 335{
5477a250 336 CStdString strLog;
fa4798bd 337
5477a250
LOK
338 va_list argList;
339 va_start(argList, strFormat);
340 strLog.FormatV(strFormat, argList);
341 va_end(argList);
342
343 CLibCEC *instance = CLibCEC::GetInstance();
344 CLockObject lock(instance->m_mutex);
345
346 cec_log_message message;
347 message.level = level;
348 message.time = GetTimeMs() - instance->m_iStartTime;
349 snprintf(message.message, sizeof(message.message), "%s", strLog.c_str());
350
351 if (instance->m_callbacks)
352 instance->m_callbacks->CBCecLogMessage(instance->m_cbParam, message);
353 else
354 instance->m_logBuffer.Push(message);
2abe74eb
LOK
355}
356
95ba7a09
LOK
357void CLibCEC::AddKey(cec_keypress &key)
358{
02e7043e
LOK
359 CLibCEC *instance = CLibCEC::GetInstance();
360 CLockObject lock(instance->m_mutex);
361
362 AddLog(CEC_LOG_DEBUG, "key pressed: %1x", key.keycode);
363
364 if (instance->m_callbacks)
365 instance->m_callbacks->CBCecKeyPress(instance->m_cbParam, key);
fa4798bd 366 else
02e7043e
LOK
367 instance->m_keyBuffer.Push(key);
368
369 instance->m_iCurrentButton = key.duration > 0 ? CEC_USER_CONTROL_CODE_UNKNOWN : key.keycode;
370 instance->m_buttontime = key.duration > 0 ? 0 : GetTimeMs();
371}
372
373void CLibCEC::SetCurrentButton(cec_user_control_code iButtonCode)
374{
375 /* push keypress to the keybuffer with 0 duration.
376 push another press to the keybuffer with the duration set when the button is released */
377 cec_keypress key;
378 key.duration = 0;
379 key.keycode = iButtonCode;
380
381 AddKey(key);
95ba7a09
LOK
382}
383
2abe74eb
LOK
384void CLibCEC::AddKey(void)
385{
02e7043e
LOK
386 CLibCEC *instance = CLibCEC::GetInstance();
387 CLockObject lock(instance->m_mutex);
388
389 if (instance->m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN)
2abe74eb
LOK
390 {
391 cec_keypress key;
25701fa6 392
02e7043e
LOK
393 key.duration = (unsigned int) (GetTimeMs() - instance->m_buttontime);
394 key.keycode = instance->m_iCurrentButton;
395 AddLog(CEC_LOG_DEBUG, "key released: %1x", key.keycode);
fa4798bd 396
02e7043e
LOK
397 if (instance->m_callbacks)
398 instance->m_callbacks->CBCecKeyPress(instance->m_cbParam, key);
fa4798bd 399 else
02e7043e
LOK
400 instance->m_keyBuffer.Push(key);
401 instance->m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
2abe74eb 402 }
02e7043e 403 instance->m_buttontime = 0;
2abe74eb
LOK
404}
405
e9de9629 406void CLibCEC::AddCommand(const cec_command &command)
2abe74eb 407{
02e7043e
LOK
408 CLibCEC *instance = CLibCEC::GetInstance();
409 CLockObject lock(instance->m_mutex);
410
411 AddLog(CEC_LOG_NOTICE, ">> %s (%X) -> %s (%X): %s (%2X)", instance->m_cec->ToString(command.initiator), command.initiator, instance->m_cec->ToString(command.destination), command.destination, instance->m_cec->ToString(command.opcode), command.opcode);
412
413 if (instance->m_callbacks)
414 instance->m_callbacks->CBCecCommand(instance->m_cbParam, command);
415 else if (!instance->m_commandBuffer.Push(command))
2abe74eb 416 AddLog(CEC_LOG_WARNING, "command buffer is full");
2abe74eb
LOK
417}
418
419void CLibCEC::CheckKeypressTimeout(void)
420{
421 if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && GetTimeMs() - m_buttontime > CEC_BUTTON_TIMEOUT)
422 {
423 AddKey();
424 m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
425 }
426}
427
f42d3e0f
LOK
428bool CLibCEC::SetStreamPath(cec_logical_address iAddress)
429{
430 uint16_t iPhysicalAddress = GetDevicePhysicalAddress(iAddress);
431 if (iPhysicalAddress != 0xFFFF)
432 return SetStreamPath(iPhysicalAddress);
433 return false;
434}
435
436bool CLibCEC::SetStreamPath(uint16_t iPhysicalAddress)
437{
438 return m_cec->SetStreamPath(iPhysicalAddress);
439}
440
80b72250
LOK
441cec_logical_addresses CLibCEC::GetLogicalAddresses(void)
442{
443 cec_logical_addresses addr = m_cec->GetLogicalAddresses();
444 return addr;
445}
446
5477a250
LOK
447static CLibCEC *g_libCEC_instance(NULL);
448CLibCEC *CLibCEC::GetInstance(void)
449{
450 return g_libCEC_instance;
451}
452
453void CLibCEC::SetInstance(CLibCEC *instance)
454{
455 if (g_libCEC_instance)
456 delete g_libCEC_instance;
457 g_libCEC_instance = instance;
458}
459
4f362964 460void * CECInit(const char *strDeviceName, CEC::cec_device_type_list types, uint16_t iPhysicalAddress /* = 0 */)
f8513317 461{
5477a250
LOK
462 CLibCEC *lib = new CLibCEC(strDeviceName, types);
463 CLibCEC::SetInstance(lib);
464 return static_cast< void* > (lib);
f8513317
LOK
465}
466
5477a250 467void CECDestroy(CEC::ICECAdapter *UNUSED(instance))
25701fa6 468{
5477a250 469 CLibCEC::SetInstance(NULL);
25701fa6 470}
03ae897d
LOK
471
472const char *CLibCEC::ToString(const cec_menu_state state)
473{
474 return m_cec->ToString(state);
475}
476
477const char *CLibCEC::ToString(const cec_version version)
478{
479 return m_cec->ToString(version);
480}
481
482const char *CLibCEC::ToString(const cec_power_status status)
483{
484 return m_cec->ToString(status);
485}
486
487const char *CLibCEC::ToString(const cec_logical_address address)
488{
489 return m_cec->ToString(address);
490}
491
492const char *CLibCEC::ToString(const cec_deck_control_mode mode)
493{
494 return m_cec->ToString(mode);
495}
496
497const char *CLibCEC::ToString(const cec_deck_info status)
498{
499 return m_cec->ToString(status);
500}
501
502const char *CLibCEC::ToString(const cec_opcode opcode)
503{
504 return m_cec->ToString(opcode);
505}
506
507const char *CLibCEC::ToString(const cec_system_audio_status mode)
508{
509 return m_cec->ToString(mode);
510}
511
512const char *CLibCEC::ToString(const cec_audio_status status)
513{
514 return m_cec->ToString(status);
515}
516
517const char *CLibCEC::ToString(const cec_vendor_id vendor)
518{
519 return m_cec->ToString(vendor);
520}