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