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
31 #include "libffado/ffado.h"
33 #include "debugmodule/debugmodule.h"
35 #include "devicemanager.h"
36 #include "ffadodevice.h"
50 #include "libieee1394/cycletimer.h"
54 DECLARE_GLOBAL_DEBUG_MODULE
;
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"
69 " SetSplitTimeout timeout_usec\n"
73 // A description of the arguments we accept.
74 static char args_doc
[] = "OPERATION";
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" },
98 {"node", 'n', "id", 0, "Node to use" },
99 {"port", 'p', "nr", 0, "IEEE1394 Port to use" },
103 //-------------------------------------------------------------
105 // Parse a single option.
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
;
117 arguments
->silent
= 1;
121 arguments
->verbose
= strtol( arg
, &tail
, 0 );
123 fprintf( stderr
, "Could not parse 'verbose' argument\n" );
124 return ARGP_ERR_UNKNOWN
;
130 arguments
->use_cache
= strtol( arg
, &tail
, 0 );
132 fprintf( stderr
, "Could not parse 'cache' argument\n" );
133 return ARGP_ERR_UNKNOWN
;
139 arguments
->port
= strtol( arg
, &tail
, 0 );
141 fprintf( stderr
, "Could not parse 'port' argument\n" );
142 return ARGP_ERR_UNKNOWN
;
146 fprintf( stderr
, "Could not parse 'port' argumen\n" );
147 return ARGP_ERR_UNKNOWN
;
153 arguments
->node_id
= strtol( arg
, &tail
, 0 );
155 fprintf( stderr
, "Could not parse 'node' argument\n" );
156 return ARGP_ERR_UNKNOWN
;
158 arguments
->node_id_set
=1;
161 fprintf( stderr
, "Could not parse 'node' argumen\n" );
162 return ARGP_ERR_UNKNOWN
;
167 if (state
->arg_num
>= MAX_ARGS
) {
168 // Too many arguments.
171 arguments
->args
[state
->arg_num
] = arg
;
175 if (state
->arg_num
< 1) {
176 // Not enough arguments.
181 return ARGP_ERR_UNKNOWN
;
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" );
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
);
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());
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
);
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);
261 arguments
.silent
= 0;
262 arguments
.verbose
= 0;
263 arguments
.use_cache
= 1;
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
++) {
309 } else if ( strcmp( arguments
.args
[0], "SetSamplerate" ) == 0 ) {
311 int samplerate
= strtol( arguments
.args
[1], &tail
, 0 );
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
);
342 avDevice
->setVerboseLevel(arguments
.verbose
);
343 if ( ! avDevice
->setSamplingFrequency( samplerate
) ) {
344 fprintf( stderr
, "Could not set samplerate\n" );
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
);
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 ) {
369 unsigned int targetid
= (unsigned int)strtol( arguments
.args
[1], &tail
, 0 );
371 fprintf( stderr
, "Could not parse clock source argument\n" );
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
);
399 FFADODevice::ClockSource s
;
401 avDevice
->setVerboseLevel(arguments
.verbose
);
402 FFADODevice::ClockSourceVector sources
=avDevice
->getSupportedClockSources();
403 for ( FFADODevice::ClockSourceVector::const_iterator 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
) {
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" );
423 printf(" no clock source with id %d found\n", targetid
);
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 ) {
433 int usecs
= strtol( arguments
.args
[1], &tail
, 0 );
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);
448 if(arguments
.node_id_set
) {
449 nodeid
= arguments
.node_id
;
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);
471 if(arguments
.node_id_set
) {
472 nodeid
= arguments
.node_id
;
474 nodeid
= service
.getLocalNodeId();
476 int usecs
= service
.getSplitTimeoutUsecs(nodeid
);
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");
491 uint64_t syt_timestamp
= strtol(arguments
.args
[1], NULL
, 0);
493 fprintf( stderr
,"syt_timestamp parsing failed: %s\n",
497 uint32_t rcv_cycle
= strtol(arguments
.args
[2], NULL
, 0);
499 fprintf( stderr
,"rcv_cycle parsing failed: %s\n",
503 uint64_t ctr_now
= strtoll(arguments
.args
[3], NULL
, 0);
505 fprintf( stderr
,"ctr_now parsing failed: %s\n",
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
));
515 fprintf( stderr
, "please specify a command\n" );