2 * This file is part of the libCEC(R) library.
4 * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
5 * libCEC(R) is an original work, containing original code.
7 * libCEC(R) is a trademark of Pulse-Eight Limited.
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.
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.
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.
24 * Alternatively, you can license this library under a commercial license,
25 * please contact Pulse-Eight Licensing for more information.
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/
33 #include "../../include/cec.h"
41 #include "../lib/platform/threads/mutex.h"
42 #include "../lib/platform/util/timeutils.h"
43 #include "../lib/implementations/CECCommandHandler.h"
47 using namespace PLATFORM
;
49 #include <cecloader.h>
53 CMutex g_responseMutex
;
54 CCondition g_responseCondtion
;
55 cec_opcode g_lastCommand
= CEC_OPCODE_NONE
;
58 CCondition g_keyCondtion
;
59 cec_user_control_code g_lastKey
= CEC_USER_CONTROL_CODE_UNKNOWN
;
61 ICECCallbacks g_callbacks
;
62 ICECAdapter
* g_parser
;
63 cec_logical_address g_primaryAddress
;
65 inline void PrintToStdOut(const char *strFormat
, ...)
70 va_start(argList
, strFormat
);
71 strLog
.FormatV(strFormat
, argList
);
74 CLockObject
lock(g_outputMutex
);
75 cout
<< strLog
<< endl
;
78 //get the first word (separated by whitespace) from string data and place that in word
79 //then remove that word from string data
80 bool GetWord(string
& data
, string
& word
)
82 stringstream
datastream(data
);
86 if (datastream
.fail())
92 size_t pos
= data
.find(word
) + word
.length();
94 if (pos
>= data
.length())
100 data
= data
.substr(pos
);
103 datastream
.str(data
);
106 if (datastream
.fail())
112 int CecLogMessage(void *UNUSED(cbParam
), const cec_log_message
&message
)
114 switch (message
.level
)
117 PrintToStdOut("ERROR:\t%s", message
.message
);
119 case CEC_LOG_WARNING
:
120 PrintToStdOut("ERROR:\t%s", message
.message
);
129 int CecKeyPress(void *UNUSED(cbParam
), const cec_keypress
&key
)
131 CLockObject
lock(g_keyMutex
);
132 g_lastKey
= key
.keycode
;
133 g_keyCondtion
.Signal();
137 int CecCommand(void *UNUSED(cbParam
), const cec_command
&command
)
139 CLockObject
lock(g_responseMutex
);
140 g_lastCommand
= command
.opcode
;
141 g_responseCondtion
.Signal();
145 void EnableCallbacks(ICECAdapter
*adapter
)
147 g_callbacks
.CBCecLogMessage
= &CecLogMessage
;
148 g_callbacks
.CBCecKeyPress
= &CecKeyPress
;
149 g_callbacks
.CBCecCommand
= &CecCommand
;
150 adapter
->EnableCallbacks(NULL
, &g_callbacks
);
153 ICECAdapter
*CreateParser(cec_device_type_list typeList
)
155 ICECAdapter
*parser
= LibCecInit("ButtonConfig", typeList
);
159 PrintToStdOut("Cannot load libcec.dll");
161 PrintToStdOut("Cannot load libcec.so");
166 PrintToStdOut("CEC Parser created - libcec version %d.%d", parser
->GetLibVersionMajor(), parser
->GetLibVersionMinor());
171 bool ProcessConsoleCommand(string
&input
)
176 if (GetWord(input
, command
))
178 if (command
== "q" || command
== "quit")
185 bool OpenConnection(cec_device_type type
= CEC_DEVICE_TYPE_RECORDING_DEVICE
)
187 cec_device_type_list types
;
191 g_parser
= CreateParser(types
);
196 cec_adapter devices
[10];
197 uint8_t iDevicesFound
= g_parser
->FindAdapters(devices
, 10, NULL
);
198 if (iDevicesFound
<= 0)
200 PrintToStdOut("autodetect FAILED");
201 UnloadLibCec(g_parser
);
206 strPort
= devices
[0].comm
;
209 EnableCallbacks(g_parser
);
211 // start with HDMI1 on the TV
212 g_parser
->SetHDMIPort(CECDEVICE_TV
, 1);
213 PrintToStdOut("opening a connection to the CEC adapter...");
215 if (!g_parser
->Open(strPort
.c_str()))
217 PrintToStdOut("unable to open the device on port %s", strPort
.c_str());
218 UnloadLibCec(g_parser
);
222 cec_logical_addresses addr
= g_parser
->GetLogicalAddresses();
223 g_primaryAddress
= addr
.primary
;
225 PrintToStdOut("cec device opened. using logical address %X", g_primaryAddress
);
229 int8_t FindPhysicalAddressPortNumber(void)
231 PrintToStdOut("Enter the HDMI port number to which you connected your CEC adapter, followed by <enter>. Only port 1, 2, 3 or 4 are supported. Anything else will cancel this wizard.");
235 if (input
.empty() || (input
!= "1" && input
!= "2" && input
!= "3" && input
!= "4"))
237 return (int8_t)atoi(input
.c_str());
240 cec_logical_address
FindPhysicalAddressBaseDevice(void)
242 PrintToStdOut("Press 1 of your CEC adapter is connected to your TV or\npress 2 if it's connected to an AVR, followed by <enter>. Anything else will cancel this wizard.");
247 if (input
.empty() || (input
!= "1" && input
!= "2"))
249 PrintToStdOut("Exiting...");
250 return CECDEVICE_UNKNOWN
;
252 return (input
== "2") ?
253 CECDEVICE_AUDIOSYSTEM
:
257 uint16_t FindPhysicalAddress(void)
259 PrintToStdOut("=== Physical Address Configuration ===\n");
260 uint16_t iAddress(0xFFFF);
262 PrintToStdOut("Do you want to let libCEC try to autodetect the address (y/n)?");
266 if (input
== "y" || input
== "Y")
268 cec_logical_address baseDevice
= FindPhysicalAddressBaseDevice();
269 if (baseDevice
== CECDEVICE_UNKNOWN
)
272 int8_t iPortNumber
= FindPhysicalAddressPortNumber();
273 if (iPortNumber
== -1)
276 PrintToStdOut("Trying to detect the physical address...");
277 if (!g_parser
->SetHDMIPort(baseDevice
, iPortNumber
))
278 PrintToStdOut("Failed. Please enter the address manually, or restart this wizard and use different settings.");
281 iAddress
= g_parser
->GetDevicePhysicalAddress(g_primaryAddress
);
282 if (iAddress
== 0 || iAddress
== 0xFFFF)
283 PrintToStdOut("Failed. Please enter the address manually, or restart this wizard and use different settings.");
287 if (iAddress
== 0 || iAddress
== 0xFFFF)
289 PrintToStdOut("Please enter the physical address (0000 - FFFF), followed by <enter>.");
294 if (sscanf(input
.c_str(), "%x", &iAddressTmp
) == 1)
296 if (iAddressTmp
< 0 || iAddressTmp
> 0xFFFF)
297 iAddressTmp
= 0xFFFF;
298 iAddress
= (uint16_t)iAddressTmp
;
305 bool PowerOnTV(uint64_t iTimeout
= 60000, unsigned iTries
= 2)
307 cec_power_status
currentTvPower(CEC_POWER_STATUS_UNKNOWN
);
308 uint64_t iNow
= GetTimeMs();
309 uint64_t iTarget
= iNow
+ iTimeout
;
312 while (currentTvPower
!= CEC_POWER_STATUS_ON
&& iTarget
> iNow
&& iTry
< iTries
)
314 currentTvPower
= g_parser
->GetDevicePowerStatus(CECDEVICE_TV
);
315 if (currentTvPower
!= CEC_POWER_STATUS_ON
)
317 PrintToStdOut("Sending 'power on' command to the TV");
318 g_parser
->PowerOnDevices(CECDEVICE_TV
);
319 while (iTarget
> iNow
)
321 CLockObject
lock(g_responseMutex
);
322 g_responseCondtion
.Wait(g_responseMutex
, (uint32_t)((iTarget
- iNow
)/iTries
));
323 if (g_lastCommand
== CEC_OPCODE_REQUEST_ACTIVE_SOURCE
)
330 currentTvPower
= g_parser
->GetDevicePowerStatus(CECDEVICE_TV
);
332 if (currentTvPower
!= CEC_POWER_STATUS_ON
)
333 PrintToStdOut("Failed to power on the TV, or the TV does not respond properly");
335 return currentTvPower
== CEC_POWER_STATUS_ON
;
338 int main (int argc
, char *argv
[])
340 PrintToStdOut("=== USB-CEC Adapter Configuration ===\n");
341 if (!OpenConnection())
347 bool bAddressOk(false);
348 uint16_t iAddress(0xFFFF);
351 iAddress
= FindPhysicalAddress();
353 PrintToStdOut("Physical address: %4X", iAddress
);
354 PrintToStdOut("Is this correct (y/n)?");
358 bAddressOk
= (input
== "y" || input
== "Y");
361 PrintToStdOut("=== USB-CEC Adapter Configuration Summary ===\n");
362 PrintToStdOut("Physical address: %4X", iAddress
);
364 g_parser
->StandbyDevices();
366 UnloadLibCec(g_parser
);
368 PrintToStdOut("Press enter to close this wizard.");