This should have been a part of r2210.
[ffado.git] / libffado / tests / test-ffado.cpp
blobb0b6e0a0b0d5ed3df4ee1b43c6c34a4f2ac67dc2
1 /*
2 * Copyright (C) 2005-2008 by Daniel Wagner
3 * Copyright (C) 2005-2008 by Pieter Palmers
5 * This file is part of FFADO
6 * FFADO = Free Firewire (pro-)audio drivers for linux
8 * FFADO is based upon FreeBoB.
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) version 3 of the License.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 * This version uses the CPP API
29 #include "version.h"
31 #include "libffado/ffado.h"
33 #include "debugmodule/debugmodule.h"
34 #include "fbtypes.h"
35 #include "devicemanager.h"
36 #include "ffadodevice.h"
38 #include <signal.h>
40 #include <argp.h>
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <string.h>
45 #include <vector>
46 #include <string>
47 #include <iostream>
48 #include <sstream>
50 #include "libieee1394/cycletimer.h"
52 using namespace std;
54 DECLARE_GLOBAL_DEBUG_MODULE;
56 #define MAX_ARGS 5
58 // global's
59 const char *argp_program_version = PACKAGE_STRING;
60 const char *argp_program_bug_address = PACKAGE_BUGREPORT;
62 // Program documentation.
63 static char doc[] = "FFADO -- a driver for Firewire Audio devices (test application)\n\n"
64 "OPERATION: Discover\n"
65 " SetSamplerate samplerate\n"
66 " SetClockSource [id]\n"
67 " BusReset\n"
68 " ListDevices\n"
69 " SetSplitTimeout timeout_usec\n"
70 " GetSplitTimeout\n"
73 // A description of the arguments we accept.
74 static char args_doc[] = "OPERATION";
76 struct arguments
78 unsigned int nargs;
79 short silent;
80 long int verbose;
81 long int port;
82 long int use_cache;
83 long int node_id;
84 long int node_id_set;
85 const char* args[MAX_ARGS];
88 // The options we understand.
89 static struct argp_option options[] = {
90 {"quiet", 'q', 0, 0, "Don't produce any output" },
91 {"silent", 's', 0, OPTION_ALIAS },
93 {"verbose", 'v', "level", 0, "Produce verbose output" },
94 #if ENABLE_DISCOVERY_CACHE
95 {"cache", 'c', "enable", 0, "Use AVC model cache" },
96 #endif
98 {"node", 'n', "id", 0, "Node to use" },
99 {"port", 'p', "nr", 0, "IEEE1394 Port to use" },
100 { 0 }
103 //-------------------------------------------------------------
105 // Parse a single option.
106 static error_t
107 parse_opt( int key, char* arg, struct argp_state* state )
109 // Get the input argument from `argp_parse', which we
110 // know is a pointer to our arguments structure.
111 struct arguments* arguments = ( struct arguments* ) state->input;
112 char* tail;
114 errno = 0;
115 switch (key) {
116 case 'q': case 's':
117 arguments->silent = 1;
118 break;
119 case 'v':
120 if (arg) {
121 arguments->verbose = strtol( arg, &tail, 0 );
122 if ( errno ) {
123 fprintf( stderr, "Could not parse 'verbose' argument\n" );
124 return ARGP_ERR_UNKNOWN;
127 break;
128 case 'c':
129 if (arg) {
130 arguments->use_cache = strtol( arg, &tail, 0 );
131 if ( errno ) {
132 fprintf( stderr, "Could not parse 'cache' argument\n" );
133 return ARGP_ERR_UNKNOWN;
136 break;
137 case 'p':
138 if (arg) {
139 arguments->port = strtol( arg, &tail, 0 );
140 if ( errno ) {
141 fprintf( stderr, "Could not parse 'port' argument\n" );
142 return ARGP_ERR_UNKNOWN;
144 } else {
145 if ( errno ) {
146 fprintf( stderr, "Could not parse 'port' argumen\n" );
147 return ARGP_ERR_UNKNOWN;
150 break;
151 case 'n':
152 if (arg) {
153 arguments->node_id = strtol( arg, &tail, 0 );
154 if ( errno ) {
155 fprintf( stderr, "Could not parse 'node' argument\n" );
156 return ARGP_ERR_UNKNOWN;
158 arguments->node_id_set=1;
159 } else {
160 if ( errno ) {
161 fprintf( stderr, "Could not parse 'node' argumen\n" );
162 return ARGP_ERR_UNKNOWN;
165 break;
166 case ARGP_KEY_ARG:
167 if (state->arg_num >= MAX_ARGS) {
168 // Too many arguments.
169 argp_usage( state );
171 arguments->args[state->arg_num] = arg;
172 arguments->nargs++;
173 break;
174 case ARGP_KEY_END:
175 if (state->arg_num < 1) {
176 // Not enough arguments.
177 argp_usage( state );
179 break;
180 default:
181 return ARGP_ERR_UNKNOWN;
183 return 0;
186 // Our argp parser.
187 static struct argp argp = { options, parse_opt, args_doc, doc };
189 int exitfunction( int retval ) {
190 debugOutput( DEBUG_LEVEL_NORMAL, "Debug output flushed...\n" );
191 flushDebugOutput();
193 return retval;
196 void
197 printDeviceList(unsigned int port)
199 Ieee1394Service service;
200 // switch off all messages since they mess up the list
201 service.setVerboseLevel(0);
202 if ( !service.initialize( port ) ) {
203 printf("Could not initialize IEEE 1394 service on port %d\n", port);
204 exit(-1);
207 printf("=== 1394 PORT %d ===\n", port);
208 printf(" Node id GUID VendorId ModelId Vendor - Model\n");
209 for (int i = 0; i < service.getNodeCount(); i++) {
210 ConfigRom crom(service, i);
211 if (crom.initialize())
212 printf(" %2d 0x%s 0x%08X 0x%08X %s - %s\n",
213 i, crom.getGuidString().c_str(),
214 crom.getNodeVendorId(), crom.getModelId(),
215 crom.getVendorName().c_str(),
216 crom.getModelName().c_str());
220 void
221 busreset(unsigned int port)
223 Ieee1394Service service;
224 // switch off all messages since they mess up the list
225 service.setVerboseLevel(0);
226 if ( !service.initialize( port ) ) {
227 printf("Could not initialize IEEE 1394 service on port %d\n", port);
228 exit(-1);
231 printf("Doing busreset on port %d\n", port);
232 service.doBusReset();
236 main( int argc, char **argv )
238 struct arguments arguments;
240 printf("-----------------------------------------------\n");
241 printf("FFADO test and diagnostic utility\n");
242 printf("Part of the FFADO project -- www.ffado.org\n");
243 printf("Version: %s\n", PACKAGE_VERSION);
244 printf("(C) 2008, Daniel Wagner, Pieter Palmers\n");
245 printf("This program comes with ABSOLUTELY NO WARRANTY.\n");
246 printf("-----------------------------------------------\n\n");
248 // check the library version
249 const char *libversion = ffado_get_version();
250 const char *progversion = PACKAGE_STRING;
251 if(strcmp(libversion, progversion) != 0) {
252 printf("Library version mismatch. (required: %s, present: %s)\n", progversion, libversion);
253 printf("Please run this application against the exact corresponding library\n");
254 printf("it was compiled for. The most common cause for this is having more\n");
255 printf("than one version of libffado installed.\n\n");
256 return exitfunction(-1);
259 // Default values.
260 arguments.nargs = 0;
261 arguments.silent = 0;
262 arguments.verbose = 0;
263 arguments.use_cache = 1;
264 arguments.port = 0;
265 arguments.node_id = 0;
266 arguments.node_id_set = 0; // if we don't specify a node, discover all
267 arguments.args[0] = "";
268 arguments.args[1] = "";
270 // Parse our arguments; every option seen by `parse_opt' will
271 // be reflected in `arguments'.
272 if ( argp_parse ( &argp, argc, argv, 0, 0, &arguments ) ) {
273 fprintf( stderr, "Could not parse command line\n" );
274 return exitfunction(-1);
276 setDebugLevel(arguments.verbose);
278 if ( strcmp( arguments.args[0], "Discover" ) == 0 ) {
279 DeviceManager *m_deviceManager = new DeviceManager();
280 if ( !m_deviceManager ) {
281 fprintf( stderr, "Could not allocate device manager\n" );
282 return exitfunction(-1);
284 if ( arguments.verbose ) {
285 m_deviceManager->setVerboseLevel(arguments.verbose);
287 if ( !m_deviceManager->initialize() ) {
288 fprintf( stderr, "Could not initialize device manager\n" );
289 delete m_deviceManager;
290 return exitfunction(-1);
292 if ( arguments.verbose ) {
293 m_deviceManager->setVerboseLevel(arguments.verbose);
295 if ( !m_deviceManager->discover(arguments.use_cache) ) {
296 fprintf( stderr, "Could not discover devices\n" );
297 delete m_deviceManager;
298 return exitfunction(-1);
300 delete m_deviceManager;
301 return exitfunction(0);
302 } else if ( strcmp( arguments.args[0], "BusReset" ) == 0 ) {
303 busreset(arguments.port);
304 } else if ( strcmp( arguments.args[0], "ListDevices" ) == 0 ) {
305 unsigned int nb_ports = Ieee1394Service::detectNbPorts();
306 for (unsigned int i=0;i<nb_ports;i++) {
307 printDeviceList(i);
309 } else if ( strcmp( arguments.args[0], "SetSamplerate" ) == 0 ) {
310 char* tail;
311 int samplerate = strtol( arguments.args[1], &tail, 0 );
312 if ( errno ) {
313 fprintf( stderr, "Could not parse samplerate argument\n" );
314 return exitfunction(-1);
317 DeviceManager *m_deviceManager = new DeviceManager();
318 if ( !m_deviceManager ) {
319 fprintf( stderr, "Could not allocate device manager\n" );
320 return exitfunction(-1);
322 if ( arguments.verbose ) {
323 m_deviceManager->setVerboseLevel(arguments.verbose);
325 if ( !m_deviceManager->initialize() ) {
326 fprintf( stderr, "Could not initialize device manager\n" );
327 delete m_deviceManager;
328 return exitfunction(-1);
330 if ( arguments.verbose ) {
331 m_deviceManager->setVerboseLevel(arguments.verbose);
333 if ( !m_deviceManager->discover(arguments.use_cache) ) {
334 fprintf( stderr, "Could not discover devices\n" );
335 delete m_deviceManager;
336 return exitfunction(-1);
339 if(arguments.node_id_set) {
340 FFADODevice* avDevice = m_deviceManager->getAvDevice( arguments.node_id );
341 if ( avDevice ) {
342 avDevice->setVerboseLevel(arguments.verbose);
343 if ( ! avDevice->setSamplingFrequency( samplerate ) ) {
344 fprintf( stderr, "Could not set samplerate\n" );
347 } else {
348 int i=0;
350 int devices_on_bus = m_deviceManager->getNbDevices();
351 printf(" port = %d, devices_on_bus = %d\n", (int)arguments.port, devices_on_bus);
353 for(i=0;i<devices_on_bus;i++) {
354 int node_id=m_deviceManager->getDeviceNodeId(i);
355 printf(" set samplerate for device = %d, node = %d\n", i, node_id);
356 FFADODevice* avDevice = m_deviceManager->getAvDevice( node_id );
357 if ( avDevice ) {
358 avDevice->setVerboseLevel(arguments.verbose);
359 if ( !avDevice->setSamplingFrequency( samplerate ) ) {
360 fprintf( stderr, "Could not set samplerate\n" );
365 delete m_deviceManager;
366 return exitfunction(0);
367 } else if ( strcmp( arguments.args[0], "SetClockSource" ) == 0 ) {
368 char* tail;
369 unsigned int targetid = (unsigned int)strtol( arguments.args[1], &tail, 0 );
370 if ( errno ) {
371 fprintf( stderr, "Could not parse clock source argument\n" );
372 targetid=0xFFFF;
374 DeviceManager *m_deviceManager = new DeviceManager();
375 if ( !m_deviceManager ) {
376 fprintf( stderr, "Could not allocate device manager\n" );
377 return exitfunction(-1);
379 if ( arguments.verbose ) {
380 m_deviceManager->setVerboseLevel(arguments.verbose);
382 if ( !m_deviceManager->initialize() ) {
383 fprintf( stderr, "Could not initialize device manager\n" );
384 delete m_deviceManager;
385 return exitfunction(-1);
387 if ( arguments.verbose ) {
388 m_deviceManager->setVerboseLevel(arguments.verbose);
390 if ( !m_deviceManager->discover(arguments.use_cache) ) {
391 fprintf( stderr, "Could not discover devices\n" );
392 delete m_deviceManager;
393 return exitfunction(-1);
396 if(arguments.node_id_set) {
397 FFADODevice* avDevice = m_deviceManager->getAvDevice( arguments.node_id );
398 if ( avDevice ) {
399 FFADODevice::ClockSource s;
401 avDevice->setVerboseLevel(arguments.verbose);
402 FFADODevice::ClockSourceVector sources=avDevice->getSupportedClockSources();
403 for ( FFADODevice::ClockSourceVector::const_iterator it
404 = sources.begin();
405 it != sources.end();
406 ++it )
408 FFADODevice::ClockSource c=*it;
409 printf( " Type: %s, Id: %d, Valid: %d, Active: %d, Description: %s\n",
410 FFADODevice::ClockSourceTypeToString(c.type), c.id, c.valid, c.active, c.description.c_str());
412 if (c.id==targetid) {
413 s=*it;
417 if (s.type != FFADODevice::eCT_Invalid) {
418 printf(" set clock source to %d\n", s.id);
419 if ( ! avDevice->setActiveClockSource( s ) ) {
420 fprintf( stderr, "Could not set clock source\n" );
422 } else {
423 printf(" no clock source with id %d found\n", targetid);
426 } else {
427 fprintf( stderr, "please specify a node\n" );
429 delete m_deviceManager;
430 return exitfunction(0);
431 } else if ( strcmp( arguments.args[0], "SetSplitTimeout" ) == 0 ) {
432 char* tail;
433 int usecs = strtol( arguments.args[1], &tail, 0 );
434 if ( errno ) {
435 fprintf( stderr, "Could not parse timeout argument\n" );
436 return exitfunction(-1);
439 Ieee1394Service service;
440 // switch off all messages since they mess up the list
441 service.setVerboseLevel(arguments.verbose);
442 if ( !service.initialize( arguments.port ) ) {
443 printf("Could not initialize IEEE 1394 service on port %d\n", (int)arguments.port);
444 return exitfunction(-1);
447 nodeid_t nodeid;
448 if(arguments.node_id_set) {
449 nodeid = arguments.node_id;
450 } else {
451 nodeid = service.getLocalNodeId();
454 if (!service.setSplitTimeoutUsecs(nodeid, usecs)) {
455 printf("Failed to set SPLIT_TIMEOUT to %u for node %X on port %d\n",
456 usecs, nodeid, (int)arguments.port);
457 return exitfunction(-1);
460 return exitfunction(0);
461 } else if ( strcmp( arguments.args[0], "GetSplitTimeout" ) == 0 ) {
462 Ieee1394Service service;
463 // switch off all messages since they mess up the list
464 service.setVerboseLevel(arguments.verbose);
465 if ( !service.initialize( arguments.port ) ) {
466 printf("Could not initialize IEEE 1394 service on port %d\n", (int)arguments.port);
467 return exitfunction(-1);
470 nodeid_t nodeid;
471 if(arguments.node_id_set) {
472 nodeid = arguments.node_id;
473 } else {
474 nodeid = service.getLocalNodeId();
476 int usecs = service.getSplitTimeoutUsecs(nodeid);
477 if (usecs < 0) {
478 printf("Failed to get SPLIT_TIMEOUT for node %X on port %d\n",
479 nodeid, (int)arguments.port);
480 return exitfunction(-1);
482 printf("SPLIT_TIMEOUT for node %X on port %d is %u\n",
483 nodeid, (int)arguments.port, usecs);
485 return exitfunction(0);
486 } else if ( strcmp( arguments.args[0], "SytCalcTest" ) == 0 ) {
487 if (arguments.nargs < 4) {
488 fprintf( stderr,"Not enough arguments\n");
489 return -1;
491 uint64_t syt_timestamp = strtol(arguments.args[1], NULL, 0);
492 if (errno) {
493 fprintf( stderr,"syt_timestamp parsing failed: %s\n",
494 strerror(errno));
495 return errno;
497 uint32_t rcv_cycle = strtol(arguments.args[2], NULL, 0);
498 if (errno) {
499 fprintf( stderr,"rcv_cycle parsing failed: %s\n",
500 strerror(errno));
501 return errno;
503 uint64_t ctr_now = strtoll(arguments.args[3], NULL, 0);
504 if (errno) {
505 fprintf( stderr,"ctr_now parsing failed: %s\n",
506 strerror(errno));
507 return errno;
509 uint64_t result_rcv = sytRecvToFullTicks(syt_timestamp, rcv_cycle, ctr_now);
510 uint64_t result_xmt = sytXmitToFullTicks(syt_timestamp, rcv_cycle, ctr_now);
511 printf("RCV: 0x%010"PRIX64" %010"PRIu64" XMT: 0x%010"PRIX64" %010"PRIu64" CTR: %010"PRIu64"\n",
512 result_rcv, result_rcv, result_xmt, result_xmt, CYCLE_TIMER_TO_TICKS(ctr_now));
514 } else {
515 fprintf( stderr, "please specify a command\n" );