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