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