cec: added option to change the log level to cec-client
[deb_libcec.git] / src / testclient / main.cpp
CommitLineData
abbca718
LOK
1/*
2 * This file is part of the libCEC(R) library.
3 *
4 * libCEC(R) is Copyright (C) 2011 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
761dcc45 33#include <cec.h>
acec5f48 34
abbca718
LOK
35#include <cstdio>
36#include <fcntl.h>
37#include <iostream>
38#include <string>
b9187cc6 39#include <sstream>
acec5f48
LOK
40#include "../lib/platform/threads.h"
41#include "../lib/util/StdString.h"
abbca718
LOK
42
43using namespace CEC;
44using namespace std;
45
8b7e5ff6 46#define CEC_TEST_CLIENT_VERSION 8
abbca718 47
761dcc45 48#include <cecloader.h>
bdd433cb 49int g_cecLogLevel = CEC_LOG_ALL;
b9187cc6 50
8bca69de 51inline bool HexStrToInt(const std::string& data, uint8_t& value)
b9187cc6 52{
8bca69de
LOK
53 int iTmp(0);
54 if (sscanf(data.c_str(), "%x", &iTmp) == 1)
55 {
56 if (iTmp > 256)
57 value = 255;
58 else if (iTmp < 0)
59 value = 0;
60 else
61 value = (uint8_t) iTmp;
b9187cc6 62
8bca69de
LOK
63 return true;
64 }
65
66 return false;
67}
b9187cc6
LOK
68
69//get the first word (separated by whitespace) from string data and place that in word
70//then remove that word from string data
71bool GetWord(string& data, string& word)
72{
73 stringstream datastream(data);
74 string end;
75
76 datastream >> word;
77 if (datastream.fail())
78 {
79 data.clear();
80 return false;
81 }
82
83 size_t pos = data.find(word) + word.length();
84
85 if (pos >= data.length())
86 {
87 data.clear();
88 return true;
89 }
90
91 data = data.substr(pos);
92
93 datastream.clear();
94 datastream.str(data);
95
96 datastream >> end;
97 if (datastream.fail())
98 data.clear();
99
100 return true;
101}
102
2abe74eb 103void flush_log(ICECAdapter *cecParser)
abbca718
LOK
104{
105 cec_log_message message;
106 while (cecParser && cecParser->GetNextLogMessage(&message))
107 {
bdd433cb 108 if ((message.level & g_cecLogLevel) == message.level)
abbca718 109 {
bdd433cb
LOK
110 switch (message.level)
111 {
112 case CEC_LOG_ERROR:
113 cout << "ERROR: ";
114 break;
115 case CEC_LOG_WARNING:
116 cout << "WARNING: ";
117 break;
118 case CEC_LOG_NOTICE:
119 cout << "NOTICE: ";
120 break;
121 case CEC_LOG_TRAFFIC:
122 cout << "TRAFFIC: ";
123 break;
124 case CEC_LOG_DEBUG:
125 cout << "DEBUG: ";
126 break;
127 default:
128 break;
129 }
40339852 130
bdd433cb
LOK
131 CStdString strMessageTmp;
132 strMessageTmp.Format("[%16lld]\t%s", message.time, message.message);
133 cout << strMessageTmp.c_str() << endl;
134 }
abbca718
LOK
135 }
136}
137
2abe74eb 138void list_devices(ICECAdapter *parser)
abbca718 139{
25701fa6
LOK
140 cec_adapter *devices = new cec_adapter[10];
141 uint8_t iDevicesFound = parser->FindAdapters(devices, 10, NULL);
abbca718
LOK
142 if (iDevicesFound <= 0)
143 {
25701fa6 144 cout << "Found devices: NONE" << endl;
abbca718
LOK
145 }
146 else
147 {
25701fa6
LOK
148 CStdString strLog;
149 strLog.Format("Found devices: %d", iDevicesFound);
150 cout << strLog.c_str() << endl;
151 for (unsigned int iDevicePtr = 0; iDevicePtr < iDevicesFound; iDevicePtr++)
abbca718
LOK
152 {
153 CStdString strDevice;
25701fa6 154 strDevice.Format("device: %d\npath: %s\ncom port: %s", iDevicePtr + 1, devices[iDevicePtr].path, devices[iDevicePtr].comm);
abbca718
LOK
155 cout << endl << strDevice.c_str() << endl;
156 }
157 }
158}
159
160void show_help(const char* strExec)
161{
162 cout << endl <<
163 strExec << " {-h|--help|-l|--list-devices|[COM PORT]}" << endl <<
164 endl <<
165 "parameters:" << endl <<
166 "\t-h --help Shows this help text" << endl <<
167 "\t-l --list-devices List all devices on this system" << endl <<
825ddb96
LOK
168 "\t[COM PORT] The com port to connect to. If no COM port is given, the client tries to connect to the first device that is detected" << endl <<
169 endl <<
170 "Type 'h' or 'help' and press enter after starting the client to display all available commands" << endl;
171}
172
173void show_console_help(void)
174{
175 cout << endl <<
176 "================================================================================" << endl <<
177 "Available commands:" << endl <<
178 endl <<
179 "tx {bytes} transfer bytes over the CEC line." << endl <<
faa6a23b 180 "txn {bytes} transfer bytes and don't wait for an ACK reply." << endl <<
825ddb96
LOK
181 "[tx 40 00 FF 11 22 33] sends bytes 0x40 0x00 0xFF 0x11 0x22 0x33" << endl <<
182 endl <<
88f45c9b
LOK
183 "on {address} power on the device with the given logical address." << endl <<
184 "[on 5] power on a connected audio system" << endl <<
185 endl <<
186 "standby {address} put the device with the given address in standby mode." << endl <<
187 "[standby 0] powers off the TV" << endl <<
188 endl <<
825ddb96
LOK
189 "la {logical_address} change the logical address of the CEC adapter." << endl <<
190 "[la 4] logical address 4" << endl <<
191 endl <<
a424ebac
LOK
192 "pa {physical_address} change the physical address of the CEC adapter." << endl <<
193 "[pa 10 00] physical address 1.0.0.0" << endl <<
194 endl <<
1969b140
LOK
195 "osd {addr} {string} set OSD message on the specified device." << endl <<
196 "[osd 0 Test Message] displays 'Test Message' on the TV" << endl <<
197 endl <<
8b7e5ff6 198 "[mon] {1|0} enable or disable CEC bus monitoring." << endl <<
bdd433cb 199 "[log] {1 - 31} change the log level. see cectypes.h for values." << endl <<
825ddb96 200 "[ping] send a ping command to the CEC adapter." << endl <<
88f45c9b
LOK
201 "[bl] to let the adapter enter the bootloader, to upgrade" << endl <<
202 " the flash rom." << endl <<
203 "[r] reconnect to the CEC adapter." << endl <<
825ddb96 204 "[h] or [help] show this help." << endl <<
88f45c9b
LOK
205 "[q] or [quit] to quit the CEC test client and switch off all" << endl <<
206 " connected CEC devices." << endl <<
825ddb96 207 "================================================================================" << endl;
abbca718
LOK
208}
209
210int main (int argc, char *argv[])
211{
d54c6c91 212 ICECAdapter *parser = LoadLibCec("CECTester");
acec5f48 213 if (!parser || parser->GetMinVersion() > CEC_TEST_CLIENT_VERSION)
abbca718 214 {
acec5f48
LOK
215#ifdef __WINDOWS__
216 cout << "Cannot load libcec.dll" << endl;
217#else
218 cout << "Cannot load libcec.so" << endl;
219#endif
abbca718
LOK
220 return 1;
221 }
222 CStdString strLog;
223 strLog.Format("CEC Parser created - libcec version %d", parser->GetLibVersion());
224 cout << strLog.c_str() << endl;
225
226 //make stdin non-blocking
227#ifndef __WINDOWS__
228 int flags = fcntl(0, F_GETFL, 0);
229 flags |= O_NONBLOCK;
230 fcntl(0, F_SETFL, flags);
231#endif
232
233 string strPort;
234 if (argc < 2)
235 {
236 cout << "no serial port given. trying autodetect: ";
25701fa6
LOK
237 cec_adapter devices[10];
238 uint8_t iDevicesFound = parser->FindAdapters(devices, 10, NULL);
abbca718
LOK
239 if (iDevicesFound <= 0)
240 {
241 cout << "FAILED" << endl;
242 UnloadLibCec(parser);
243 return 1;
244 }
245 else
246 {
247 cout << endl << " path: " << devices[0].path << endl <<
248 " com port: " << devices[0].comm << endl << endl;
249 strPort = devices[0].comm;
250 }
251 }
252 else if (!strcmp(argv[1], "--list-devices") || !strcmp(argv[1], "-l"))
253 {
254 list_devices(parser);
255 UnloadLibCec(parser);
256 return 0;
257 }
258 else if (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))
259 {
260 show_help(argv[0]);
261 return 0;
262 }
263 else
264 {
265 strPort = argv[1];
266 }
267
268 if (!parser->Open(strPort.c_str()))
269 {
270 cout << "unable to open the device on port " << strPort << endl;
271 flush_log(parser);
272 UnloadLibCec(parser);
273 return 1;
274 }
275
276 cout << "cec device opened" << endl;
abbca718 277
8829d291 278 parser->PowerOnDevices(CECDEVICE_TV);
abbca718
LOK
279 flush_log(parser);
280
281 parser->SetActiveView();
282 flush_log(parser);
283
284 bool bContinue(true);
285 cout << "waiting for input" << endl;
286 while (bContinue)
287 {
288 flush_log(parser);
289
290 string input;
291 getline(cin, input);
292 cin.clear();
293
294 if (!input.empty())
295 {
296 string command;
297 if (GetWord(input, command))
298 {
faa6a23b 299 if (command == "tx" || command == "txn")
abbca718
LOK
300 {
301 string strvalue;
8bca69de 302 uint8_t ivalue;
9dee1670 303 cec_command bytes;
25701fa6
LOK
304 bytes.clear();
305
abbca718 306 while (GetWord(input, strvalue) && HexStrToInt(strvalue, ivalue))
b2da2768 307 bytes.push_back(ivalue);
abbca718 308
faa6a23b 309 parser->Transmit(bytes, command == "tx");
abbca718 310 }
88f45c9b
LOK
311 else if (command == "on")
312 {
313 string strValue;
314 uint8_t iValue = 0;
315 if (GetWord(input, strValue) && HexStrToInt(strValue, iValue) && iValue <= 0xF)
316 {
317 parser->PowerOnDevices((cec_logical_address) iValue);
318 }
319 else
320 {
321 cout << "invalid destination" << endl;
322 }
323 }
324 else if (command == "standby")
325 {
326 string strValue;
327 uint8_t iValue = 0;
328 if (GetWord(input, strValue) && HexStrToInt(strValue, iValue) && iValue <= 0xF)
329 {
330 parser->StandbyDevices((cec_logical_address) iValue);
331 }
332 else
333 {
334 cout << "invalid destination" << endl;
335 }
336 }
6dfe9213
LOK
337 else if (command == "la")
338 {
339 string strvalue;
6dfe9213
LOK
340 if (GetWord(input, strvalue))
341 {
342 parser->SetLogicalAddress((cec_logical_address) atoi(strvalue.c_str()));
abbca718
LOK
343 }
344 }
a424ebac
LOK
345 else if (command == "pa")
346 {
347 string strB1, strB2;
348 uint8_t iB1, iB2;
349 if (GetWord(input, strB1) && HexStrToInt(strB1, iB1) &&
350 GetWord(input, strB2) && HexStrToInt(strB2, iB2))
351 {
352 uint16_t iPhysicalAddress = ((uint16_t)iB1 << 8) + iB2;
353 parser->SetPhysicalAddress(iPhysicalAddress);
354 }
355 }
1969b140
LOK
356 else if (command == "osd")
357 {
358 bool bFirstWord(false);
359 string strAddr, strMessage, strWord;
360 uint8_t iAddr;
361 if (GetWord(input, strAddr) && HexStrToInt(strAddr, iAddr) && iAddr < 0xF)
362 {
363 while (GetWord(input, strWord))
364 {
365 if (bFirstWord)
366 {
367 bFirstWord = false;
368 strMessage.append(" ");
369 }
370 strMessage.append(strWord);
371 }
372 parser->SetOSDString((cec_logical_address) iAddr, CEC_DISPLAY_CONTROL_DISPLAY_FOR_DEFAULT_TIME, strMessage.c_str());
373 }
374 }
abbca718
LOK
375 else if (command == "ping")
376 {
2abe74eb 377 parser->PingAdapter();
abbca718 378 }
8b7e5ff6
LOK
379 else if (command == "mon")
380 {
381 CStdString strEnable;
382 if (GetWord(input, strEnable) && (strEnable.Equals("0") || strEnable.Equals("1")))
383 {
384 parser->SwitchMonitoring(strEnable.Equals("1"));
385 }
386 }
abbca718
LOK
387 else if (command == "bl")
388 {
389 parser->StartBootloader();
390 }
12027dbe
LOK
391 else if (command == "r")
392 {
25701fa6 393 cout << "closing the connection" << endl;
12027dbe 394 parser->Close();
25701fa6
LOK
395 flush_log(parser);
396
397 cout << "opening a new connection" << endl;
12027dbe 398 parser->Open(strPort.c_str());
25701fa6
LOK
399 flush_log(parser);
400
401 cout << "setting active view" << endl;
12027dbe
LOK
402 parser->SetActiveView();
403 }
825ddb96
LOK
404 else if (command == "h" || command == "help")
405 {
406 show_console_help();
407 }
abbca718
LOK
408 else if (command == "q" || command == "quit")
409 {
410 bContinue = false;
411 }
bdd433cb
LOK
412 else if (command == "log")
413 {
414 CStdString strLevel;
415 if (GetWord(input, strLevel))
416 {
417 int iNewLevel = atoi(strLevel);
418 if (iNewLevel >= CEC_LOG_ERROR && iNewLevel <= CEC_LOG_ALL)
419 {
420 g_cecLogLevel = iNewLevel;
421 cout << "log level changed to " << strLevel.c_str() << endl;
422 }
423 }
424 }
abbca718
LOK
425 }
426 if (bContinue)
427 cout << "waiting for input" << endl;
428 }
429 CCondition::Sleep(50);
430 }
431
2abe74eb 432 parser->StandbyDevices(CECDEVICE_BROADCAST);
5f39c4d8 433 parser->Close();
abbca718
LOK
434 flush_log(parser);
435 UnloadLibCec(parser);
436 return 0;
437}