dc20968dd60952bc7f3e42366a58cb770c95669f
[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 <libcec/CECExports.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 7
47
48 #include <libcec/CECLoader.h>
49
50 inline bool HexStrToInt(const std::string& data, uint8_t& value)
51 {
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;
61
62 return true;
63 }
64
65 return false;
66 }
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
70 bool 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
102 void flush_log(ICECAdapter *cecParser)
103 {
104 cec_log_message message;
105 while (cecParser && cecParser->GetNextLogMessage(&message))
106 {
107 switch (message.level)
108 {
109 case CEC_LOG_ERROR:
110 cout << "ERROR: ";
111 break;
112 case CEC_LOG_WARNING:
113 cout << "WARNING: ";
114 break;
115 case CEC_LOG_NOTICE:
116 cout << "NOTICE: ";
117 break;
118 case CEC_LOG_DEBUG:
119 cout << "DEBUG: ";
120 break;
121 }
122
123 CStdString strMessageTmp;
124 strMessageTmp.Format("[%16lld]\t%s", message.time, message.message);
125 cout << strMessageTmp.c_str() << endl;
126 }
127 }
128
129 void list_devices(ICECAdapter *parser)
130 {
131 cec_adapter *devices = new cec_adapter[10];
132 uint8_t iDevicesFound = parser->FindAdapters(devices, 10, NULL);
133 if (iDevicesFound <= 0)
134 {
135 cout << "Found devices: NONE" << endl;
136 }
137 else
138 {
139 CStdString strLog;
140 strLog.Format("Found devices: %d", iDevicesFound);
141 cout << strLog.c_str() << endl;
142 for (unsigned int iDevicePtr = 0; iDevicePtr < iDevicesFound; iDevicePtr++)
143 {
144 CStdString strDevice;
145 strDevice.Format("device: %d\npath: %s\ncom port: %s", iDevicePtr + 1, devices[iDevicePtr].path, devices[iDevicePtr].comm);
146 cout << endl << strDevice.c_str() << endl;
147 }
148 }
149 }
150
151 void show_help(const char* strExec)
152 {
153 cout << endl <<
154 strExec << " {-h|--help|-l|--list-devices|[COM PORT]}" << endl <<
155 endl <<
156 "parameters:" << endl <<
157 "\t-h --help Shows this help text" << endl <<
158 "\t-l --list-devices List all devices on this system" << endl <<
159 "\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 <<
160 endl <<
161 "Type 'h' or 'help' and press enter after starting the client to display all available commands" << endl;
162 }
163
164 void show_console_help(void)
165 {
166 cout << endl <<
167 "================================================================================" << endl <<
168 "Available commands:" << endl <<
169 endl <<
170 "tx {bytes} transfer bytes over the CEC line." << endl <<
171 "[tx 40 00 FF 11 22 33] sends bytes 0x40 0x00 0xFF 0x11 0x22 0x33" << endl <<
172 endl <<
173 "on {address} power on the device with the given logical address." << endl <<
174 "[on 5] power on a connected audio system" << endl <<
175 endl <<
176 "standby {address} put the device with the given address in standby mode." << endl <<
177 "[standby 0] powers off the TV" << endl <<
178 endl <<
179 "la {logical_address} change the logical address of the CEC adapter." << endl <<
180 "[la 4] logical address 4" << endl <<
181 endl <<
182 "[ping] send a ping command to the CEC adapter." << endl <<
183 "[bl] to let the adapter enter the bootloader, to upgrade" << endl <<
184 " the flash rom." << endl <<
185 "[r] reconnect to the CEC adapter." << endl <<
186 "[h] or [help] show this help." << endl <<
187 "[q] or [quit] to quit the CEC test client and switch off all" << endl <<
188 " connected CEC devices." << endl <<
189 "================================================================================" << endl;
190 }
191
192 int main (int argc, char *argv[])
193 {
194 ICECAdapter *parser = LoadLibCec("CECTester");
195 if (!parser || parser->GetMinVersion() > CEC_TEST_CLIENT_VERSION)
196 {
197 #ifdef __WINDOWS__
198 cout << "Cannot load libcec.dll" << endl;
199 #else
200 cout << "Cannot load libcec.so" << endl;
201 #endif
202 return 1;
203 }
204 CStdString strLog;
205 strLog.Format("CEC Parser created - libcec version %d", parser->GetLibVersion());
206 cout << strLog.c_str() << endl;
207
208 //make stdin non-blocking
209 #ifndef __WINDOWS__
210 int flags = fcntl(0, F_GETFL, 0);
211 flags |= O_NONBLOCK;
212 fcntl(0, F_SETFL, flags);
213 #endif
214
215 string strPort;
216 if (argc < 2)
217 {
218 cout << "no serial port given. trying autodetect: ";
219 cec_adapter devices[10];
220 uint8_t iDevicesFound = parser->FindAdapters(devices, 10, NULL);
221 if (iDevicesFound <= 0)
222 {
223 cout << "FAILED" << endl;
224 UnloadLibCec(parser);
225 return 1;
226 }
227 else
228 {
229 cout << endl << " path: " << devices[0].path << endl <<
230 " com port: " << devices[0].comm << endl << endl;
231 strPort = devices[0].comm;
232 }
233 }
234 else if (!strcmp(argv[1], "--list-devices") || !strcmp(argv[1], "-l"))
235 {
236 list_devices(parser);
237 UnloadLibCec(parser);
238 return 0;
239 }
240 else if (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))
241 {
242 show_help(argv[0]);
243 return 0;
244 }
245 else
246 {
247 strPort = argv[1];
248 }
249
250 if (!parser->Open(strPort.c_str()))
251 {
252 cout << "unable to open the device on port " << strPort << endl;
253 flush_log(parser);
254 UnloadLibCec(parser);
255 return 1;
256 }
257
258 cout << "cec device opened" << endl;
259
260 parser->PowerOnDevices(CECDEVICE_TV);
261 flush_log(parser);
262
263 parser->SetActiveView();
264 flush_log(parser);
265
266 bool bContinue(true);
267 cout << "waiting for input" << endl;
268 while (bContinue)
269 {
270 flush_log(parser);
271
272 string input;
273 getline(cin, input);
274 cin.clear();
275
276 if (!input.empty())
277 {
278 string command;
279 if (GetWord(input, command))
280 {
281 if (command == "tx")
282 {
283 string strvalue;
284 uint8_t ivalue;
285 cec_command bytes;
286 bytes.clear();
287
288 while (GetWord(input, strvalue) && HexStrToInt(strvalue, ivalue))
289 bytes.push_back(ivalue);
290
291 parser->Transmit(bytes);
292 }
293 else if (command == "on")
294 {
295 string strValue;
296 uint8_t iValue = 0;
297 if (GetWord(input, strValue) && HexStrToInt(strValue, iValue) && iValue <= 0xF)
298 {
299 parser->PowerOnDevices((cec_logical_address) iValue);
300 }
301 else
302 {
303 cout << "invalid destination" << endl;
304 }
305 }
306 else if (command == "standby")
307 {
308 string strValue;
309 uint8_t iValue = 0;
310 if (GetWord(input, strValue) && HexStrToInt(strValue, iValue) && iValue <= 0xF)
311 {
312 parser->StandbyDevices((cec_logical_address) iValue);
313 }
314 else
315 {
316 cout << "invalid destination" << endl;
317 }
318 }
319 else if (command == "la")
320 {
321 string strvalue;
322 if (GetWord(input, strvalue))
323 {
324 parser->SetLogicalAddress((cec_logical_address) atoi(strvalue.c_str()));
325 }
326 }
327 else if (command == "ping")
328 {
329 parser->PingAdapter();
330 }
331 else if (command == "bl")
332 {
333 parser->StartBootloader();
334 }
335 else if (command == "r")
336 {
337 cout << "closing the connection" << endl;
338 parser->Close();
339 flush_log(parser);
340
341 cout << "opening a new connection" << endl;
342 parser->Open(strPort.c_str());
343 flush_log(parser);
344
345 cout << "setting active view" << endl;
346 parser->SetActiveView();
347 }
348 else if (command == "h" || command == "help")
349 {
350 show_console_help();
351 }
352 else if (command == "q" || command == "quit")
353 {
354 bContinue = false;
355 }
356 }
357 if (bContinue)
358 cout << "waiting for input" << endl;
359 }
360 CCondition::Sleep(50);
361 }
362
363 parser->StandbyDevices(CECDEVICE_BROADCAST);
364 parser->Close();
365 flush_log(parser);
366 UnloadLibCec(parser);
367 return 0;
368 }