cec: added option to change the log level to cec-client
[deb_libcec.git] / src / testclient / main.cpp
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
33 #include <cec.h>
34
35 #include <cstdio>
36 #include <fcntl.h>
37 #include <iostream>
38 #include <string>
39 #include <sstream>
40 #include "../lib/platform/threads.h"
41 #include "../lib/util/StdString.h"
42
43 using namespace CEC;
44 using namespace std;
45
46 #define CEC_TEST_CLIENT_VERSION 8
47
48 #include <cecloader.h>
49 int g_cecLogLevel = CEC_LOG_ALL;
50
51 inline bool HexStrToInt(const std::string& data, uint8_t& value)
52 {
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;
62
63 return true;
64 }
65
66 return false;
67 }
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
71 bool 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
103 void flush_log(ICECAdapter *cecParser)
104 {
105 cec_log_message message;
106 while (cecParser && cecParser->GetNextLogMessage(&message))
107 {
108 if ((message.level & g_cecLogLevel) == message.level)
109 {
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 }
130
131 CStdString strMessageTmp;
132 strMessageTmp.Format("[%16lld]\t%s", message.time, message.message);
133 cout << strMessageTmp.c_str() << endl;
134 }
135 }
136 }
137
138 void list_devices(ICECAdapter *parser)
139 {
140 cec_adapter *devices = new cec_adapter[10];
141 uint8_t iDevicesFound = parser->FindAdapters(devices, 10, NULL);
142 if (iDevicesFound <= 0)
143 {
144 cout << "Found devices: NONE" << endl;
145 }
146 else
147 {
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++)
152 {
153 CStdString strDevice;
154 strDevice.Format("device: %d\npath: %s\ncom port: %s", iDevicePtr + 1, devices[iDevicePtr].path, devices[iDevicePtr].comm);
155 cout << endl << strDevice.c_str() << endl;
156 }
157 }
158 }
159
160 void 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 <<
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
173 void 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 <<
180 "txn {bytes} transfer bytes and don't wait for an ACK reply." << endl <<
181 "[tx 40 00 FF 11 22 33] sends bytes 0x40 0x00 0xFF 0x11 0x22 0x33" << endl <<
182 endl <<
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 <<
189 "la {logical_address} change the logical address of the CEC adapter." << endl <<
190 "[la 4] logical address 4" << endl <<
191 endl <<
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 <<
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 <<
198 "[mon] {1|0} enable or disable CEC bus monitoring." << endl <<
199 "[log] {1 - 31} change the log level. see cectypes.h for values." << endl <<
200 "[ping] send a ping command to the CEC adapter." << endl <<
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 <<
204 "[h] or [help] show this help." << endl <<
205 "[q] or [quit] to quit the CEC test client and switch off all" << endl <<
206 " connected CEC devices." << endl <<
207 "================================================================================" << endl;
208 }
209
210 int main (int argc, char *argv[])
211 {
212 ICECAdapter *parser = LoadLibCec("CECTester");
213 if (!parser || parser->GetMinVersion() > CEC_TEST_CLIENT_VERSION)
214 {
215 #ifdef __WINDOWS__
216 cout << "Cannot load libcec.dll" << endl;
217 #else
218 cout << "Cannot load libcec.so" << endl;
219 #endif
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: ";
237 cec_adapter devices[10];
238 uint8_t iDevicesFound = parser->FindAdapters(devices, 10, NULL);
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;
277
278 parser->PowerOnDevices(CECDEVICE_TV);
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 {
299 if (command == "tx" || command == "txn")
300 {
301 string strvalue;
302 uint8_t ivalue;
303 cec_command bytes;
304 bytes.clear();
305
306 while (GetWord(input, strvalue) && HexStrToInt(strvalue, ivalue))
307 bytes.push_back(ivalue);
308
309 parser->Transmit(bytes, command == "tx");
310 }
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 }
337 else if (command == "la")
338 {
339 string strvalue;
340 if (GetWord(input, strvalue))
341 {
342 parser->SetLogicalAddress((cec_logical_address) atoi(strvalue.c_str()));
343 }
344 }
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 }
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 }
375 else if (command == "ping")
376 {
377 parser->PingAdapter();
378 }
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 }
387 else if (command == "bl")
388 {
389 parser->StartBootloader();
390 }
391 else if (command == "r")
392 {
393 cout << "closing the connection" << endl;
394 parser->Close();
395 flush_log(parser);
396
397 cout << "opening a new connection" << endl;
398 parser->Open(strPort.c_str());
399 flush_log(parser);
400
401 cout << "setting active view" << endl;
402 parser->SetActiveView();
403 }
404 else if (command == "h" || command == "help")
405 {
406 show_console_help();
407 }
408 else if (command == "q" || command == "quit")
409 {
410 bContinue = false;
411 }
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 }
425 }
426 if (bContinue)
427 cout << "waiting for input" << endl;
428 }
429 CCondition::Sleep(50);
430 }
431
432 parser->StandbyDevices(CECDEVICE_BROADCAST);
433 parser->Close();
434 flush_log(parser);
435 UnloadLibCec(parser);
436 return 0;
437 }