root/trunk/libffado/tests/test-ieee1394service.cpp

Revision 2088, 13.9 kB (checked in by jwoithe, 12 years ago)

More fixes for compilation under gcc 4.7. Patch supplied by "oget". Fixes reopened ticket #344.

Line 
1 /*
2  * Copyright (C) 2005-2008 by Pieter Palmers
3  *
4  * This file is part of FFADO
5  * FFADO = Free Firewire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB
8  *
9  * This program is free software: 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) version 3 of the License.
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, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <endian.h>
32 #include <unistd.h>
33
34 #include <getopt.h>
35
36 #include <signal.h>
37 #include "src/debugmodule/debugmodule.h"
38
39 #include "libutil/ByteSwap.h"
40
41 #include "src/libieee1394/cycletimer.h"
42 #include "src/libieee1394/configrom.h"
43 #include "src/libieee1394/ieee1394service.h"
44
45 #include "src/libutil/Thread.h"
46 #include "src/libutil/Functors.h"
47 #include "src/libutil/PosixThread.h"
48 #include <libraw1394/raw1394.h>
49 #include "libutil/Time.h"
50
51
52 #define NB_THREADS 1
53 #define THREAD_RT  true
54 #define THREAD_PRIO 51
55 #define THREAD_SLEEP_US 50000
56
57 #define DISP_CYCLE_SLEEP_SECS 2
58
59 using namespace Util;
60
61 DECLARE_GLOBAL_DEBUG_MODULE;
62
63 #define DIFF_CONSIDERED_LARGE (TICKS_PER_CYCLE/2)
64 int PORT_TO_USE = 0;
65 int VERBOSE_LEVEL = 4;
66
67 int max_diff=-99999;
68 int min_diff= 99999;
69
70 int run=1;
71 static void sighandler (int sig)
72 {
73     run = 0;
74 }
75
76 class MyFunctor : public Functor
77 {
78 public:
79     MyFunctor() {}
80     virtual ~MyFunctor() {}
81
82     void operator() () {
83         printf("hello from the functor (%p)\n", this);
84     };
85     virtual bool matchCallee(void *) {return false;};
86 };
87
88 class CtrThread : public Util::RunnableInterface
89 {
90     public:
91         CtrThread(Ieee1394Service *s)
92         : m_service(s)
93         {};
94         virtual ~CtrThread() {};
95         virtual bool Init()
96         {
97             debugOutput(DEBUG_LEVEL_NORMAL, "(%p) Init\n", this);
98             ctr = 0;
99             ctr_dll = 0;
100        
101             ctr_prev = 0;
102             ctr_dll_prev = 0;
103             nb_checks = 0;
104             summed_diff = 0;
105             avg_diff = 0;
106             m_reset_avg = 1;
107             m_handle = raw1394_new_handle_on_port( PORT_TO_USE );
108             if ( !m_handle ) {
109                 if ( !errno ) {
110                     debugFatal("libraw1394 not compatible\n");
111                 } else {
112                     debugFatal("Ieee1394Service::initialize: Could not get 1394 handle: %s\n",
113                         strerror(errno) );
114                     debugFatal("Is ieee1394 and raw1394 driver loaded?\n");
115                 }
116                 return false;
117             }
118             return true;
119         }
120         virtual bool Execute();
121
122         Ieee1394Service *m_service;
123         raw1394handle_t m_handle;
124         uint64_t ctr;
125         uint64_t ctr_dll;
126
127         uint64_t ctr_prev;
128         uint64_t ctr_dll_prev;
129        
130         uint64_t nb_checks;
131         int64_t summed_diff;
132         double avg_diff;
133         int m_reset_avg;
134 };
135
136 bool CtrThread::Execute() {
137     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "(%p) Execute\n", this);
138    
139     SleepRelativeUsec(THREAD_SLEEP_US);
140
141     uint32_t cycle_timer;
142     uint64_t local_time;
143     uint32_t cycle_timer2;
144     uint64_t local_time2;
145     uint64_t ticks1, ticks2;
146     int err;
147
148     do {
149         // read the CTR 'raw' from a handle
150         // and read it from the 1394 service, which uses a DLL
151         err = raw1394_read_cycle_timer(m_handle, &cycle_timer2, &local_time2);
152         err = raw1394_read_cycle_timer(m_handle, &cycle_timer, &local_time);
153        
154         ticks1 = CYCLE_TIMER_TO_TICKS(cycle_timer);
155         ticks2 = CYCLE_TIMER_TO_TICKS(cycle_timer2);
156     } while (diffTicks(ticks1, ticks2) < 0);
157    
158     ctr_prev = ctr;
159     ctr_dll_prev = ctr_dll;
160    
161     ctr = CYCLE_TIMER_TO_TICKS( cycle_timer );
162     ctr_dll = m_service->getCycleTimerTicks(local_time);
163
164     if(err) {
165         debugError("(%p) CTR read error\n", this);
166     }
167     debugOutput ( DEBUG_LEVEL_VERY_VERBOSE,
168                 "(%p) Cycle timer: %011"PRIu64" (%03us %04ucy %04uticks)\n",
169                 this, ctr,
170                 (unsigned int)TICKS_TO_SECS( ctr ),
171                 (unsigned int)TICKS_TO_CYCLES( ctr ),
172                 (unsigned int)TICKS_TO_OFFSET( ctr ) );
173     debugOutput ( DEBUG_LEVEL_VERY_VERBOSE,
174                 "(%p)    from DLL: %011"PRIu64" (%03us %04ucy %04uticks)\n",
175                 this, ctr_dll,
176                 (unsigned int)TICKS_TO_SECS( ctr_dll ),
177                 (unsigned int)TICKS_TO_CYCLES( ctr_dll ),
178                 (unsigned int)TICKS_TO_OFFSET( ctr_dll ) );
179     int64_t diff = diffTicks(ctr, ctr_dll);
180     uint64_t abs_diff;
181     // for jitter plots
182     //     debugOutput(DEBUG_LEVEL_NORMAL, "9876543210: %lld\n", diff);
183
184     if(m_reset_avg) {
185         m_reset_avg = 0;
186         summed_diff = 0;
187         nb_checks = 0;
188     }
189
190     // not 100% thread safe, but will do
191     if (diff > max_diff) max_diff = diff;
192     if (diff < min_diff) min_diff = diff;
193     summed_diff += diff;
194     nb_checks++;
195     avg_diff = ((double)summed_diff)/((double)nb_checks);
196    
197     if (diff < 0) {
198         abs_diff = -diff;
199     } else {
200         abs_diff = diff;
201     }
202     debugOutput ( DEBUG_LEVEL_VERY_VERBOSE,
203                 "(%p)       diff: %s%011"PRIu64" (%03us %04ucy %04uticks)\n", this,
204                 ((int64_t)abs_diff==diff?" ":"-"), abs_diff, (unsigned int)TICKS_TO_SECS( abs_diff ),
205                 (unsigned int)TICKS_TO_CYCLES( abs_diff ), (unsigned int)TICKS_TO_OFFSET( abs_diff ) );
206     if (abs_diff > DIFF_CONSIDERED_LARGE) {
207         debugWarning("(%p) Alert, large diff: %"PRId64"\n", this, diff);
208         debugOutput ( DEBUG_LEVEL_NORMAL,
209                     "(%p)  Cycle timer: %011"PRIu64" (%03us %04ucy %04uticks)\n",
210                     this, ctr,
211                     (unsigned int)TICKS_TO_SECS( ctr ),
212                     (unsigned int)TICKS_TO_CYCLES( ctr ),
213                     (unsigned int)TICKS_TO_OFFSET( ctr ) );
214         debugOutput ( DEBUG_LEVEL_NORMAL,
215                     "(%p)   from DLL: %011"PRIu64" (%03us %04ucy %04uticks)\n",
216                     this, ctr_dll,
217                     (unsigned int)TICKS_TO_SECS( ctr_dll ),
218                     (unsigned int)TICKS_TO_CYCLES( ctr_dll ),
219                     (unsigned int)TICKS_TO_OFFSET( ctr_dll ) );
220     }
221    
222     diff = diffTicks(ctr, ctr_prev);
223     if (diff < 0) {
224         debugWarning("(%p) Alert, non-monotonic ctr (direct): %"PRId64" - %"PRId64" = %"PRId64"\n",
225                      this, ctr, ctr_prev, diff);
226         debugOutput ( DEBUG_LEVEL_NORMAL,
227                     "(%p)  Cycle timer now : %011"PRIu64" (%03us %04ucy %04uticks)\n",
228                     this, ctr,
229                     (unsigned int)TICKS_TO_SECS( ctr ),
230                     (unsigned int)TICKS_TO_CYCLES( ctr ),
231                     (unsigned int)TICKS_TO_OFFSET( ctr ) );
232         debugOutput ( DEBUG_LEVEL_NORMAL,
233                     "(%p)  Cycle timer prev: %011"PRIu64" (%03us %04ucy %04uticks)\n",
234                     this, ctr_prev,
235                     (unsigned int)TICKS_TO_SECS( ctr_prev ),
236                     (unsigned int)TICKS_TO_CYCLES( ctr_prev ),
237                     (unsigned int)TICKS_TO_OFFSET( ctr_prev ) );
238     }
239     diff = diffTicks(ctr_dll, ctr_dll_prev);
240     if (diff < 0) {
241         debugWarning("(%p) Alert, non-monotonic ctr (dll): %"PRId64" - %"PRId64" = %"PRId64"\n",
242                      this, ctr_dll, ctr_dll_prev, diff);
243         debugOutput ( DEBUG_LEVEL_NORMAL,
244                     "(%p)  Cycle timer now : %011"PRIu64" (%03us %04ucy %04uticks)\n",
245                     this, ctr_dll,
246                     (unsigned int)TICKS_TO_SECS( ctr_dll ),
247                     (unsigned int)TICKS_TO_CYCLES( ctr_dll ),
248                     (unsigned int)TICKS_TO_OFFSET( ctr_dll ) );
249         debugOutput ( DEBUG_LEVEL_NORMAL,
250                     "(%p)  Cycle timer prev: %011"PRIu64" (%03us %04ucy %04uticks)\n",
251                     this, ctr_dll_prev,
252                     (unsigned int)TICKS_TO_SECS( ctr_dll_prev ),
253                     (unsigned int)TICKS_TO_CYCLES( ctr_dll_prev ),
254                     (unsigned int)TICKS_TO_OFFSET( ctr_dll_prev ) );
255     }
256    
257     // check some calculations
258     uint32_t tmp_orig = m_service->getCycleTimer();
259     uint32_t tmp_ticks = CYCLE_TIMER_TO_TICKS(tmp_orig);
260     uint32_t tmp_ctr = TICKS_TO_CYCLE_TIMER(tmp_ticks);
261    
262     if (tmp_orig != tmp_ctr) {
263         debugError("CTR => TICKS => CTR failed\n");
264         debugOutput ( DEBUG_LEVEL_VERY_VERBOSE,
265                     "(%p) orig CTR : %08X (%03us %04ucy %04uticks)\n",
266                     this, (uint32_t)tmp_orig,
267                     (unsigned int)CYCLE_TIMER_GET_SECS( tmp_orig ),
268                     (unsigned int)CYCLE_TIMER_GET_CYCLES( tmp_orig ),
269                     (unsigned int)CYCLE_TIMER_GET_OFFSET( tmp_orig ) );
270         debugOutput ( DEBUG_LEVEL_VERY_VERBOSE,
271                     "(%p) TICKS: %011"PRIu32" (%03us %04ucy %04uticks)\n",
272                     this, tmp_ticks,
273                     (unsigned int)TICKS_TO_SECS( tmp_ticks ),
274                     (unsigned int)TICKS_TO_CYCLES( tmp_ticks ),
275                     (unsigned int)TICKS_TO_OFFSET( tmp_ticks ) );
276         debugOutput ( DEBUG_LEVEL_VERY_VERBOSE,
277                     "(%p) new CTR : %08X (%03us %04ucy %04uticks)\n",
278                     this, (uint32_t)tmp_ctr,
279                     (unsigned int)CYCLE_TIMER_GET_SECS( tmp_ctr ),
280                     (unsigned int)CYCLE_TIMER_GET_CYCLES( tmp_ctr ),
281                     (unsigned int)CYCLE_TIMER_GET_OFFSET( tmp_ctr ) );
282     }
283    
284     debugOutput ( DEBUG_LEVEL_VERY_VERBOSE,
285                 "(%p)  wait...\n", this);
286     return true;
287 }
288
289 int main(int argc, char *argv[])
290 {
291     int i=0;
292     signal (SIGINT, sighandler);
293     signal (SIGPIPE, sighandler);
294
295     static struct option long_opts[] = { { "port", 1, 0, 'p' },  { "verbose", 1, 0, 'v' }, { "help", 0, 0, 'h' }, { 0, 0, 0, 0 } };
296     int optindex = 0;
297     while(1) {
298         int c = getopt_long( argc, argv, "p:h", long_opts, &optindex );
299         if(c==-1)
300             break;
301         switch(c) {
302             case 'p':
303                 PORT_TO_USE = atoi( optarg );
304                 break;
305             case 'v':
306                 VERBOSE_LEVEL = atoi( optarg );
307                 break;
308             case 'h':
309                 printf( "USAGE:\n\
310  Currently two options are understood:\n\
311   --port <number> or -p <number> selects the firewire-port to use, default is 0\n\
312   --verbose <number> or -v <number> selects the verbose level, default is 4\n\
313   --help or -h shows this help and exits.\n\
314 " );
315                 return 0;
316                 break;
317         }
318     }
319
320     printf("FFADO Ieee1394Service test application\n");
321     printf(" Using port %d\n", PORT_TO_USE);
322     printf(" Verbose level %d\n", VERBOSE_LEVEL);
323
324     setDebugLevel(VERBOSE_LEVEL);
325
326     Ieee1394Service *m_service=NULL;
327
328     m_service = new Ieee1394Service();
329     m_service->setVerboseLevel(VERBOSE_LEVEL);
330     if(!m_service->initialize(PORT_TO_USE)) {
331         printf("Could not initialize 1394 service\n");
332         delete m_service;
333         exit(-1);
334     }
335     m_service->setThreadParameters(true, 1);
336
337     MyFunctor *test_busreset=new MyFunctor();
338
339     printf(" adding (%p) as busreset handler\n", test_busreset);
340
341     m_service->addBusResetHandler(test_busreset);
342
343     nodeaddr_t addr =  m_service->findFreeARMBlock(0x0000FFFFE0000000ULL, 4, 4 );
344
345     Ieee1394Service::ARMHandler *test_arm = new Ieee1394Service::ARMHandler(*m_service, addr,
346                            4,
347                            RAW1394_ARM_READ | RAW1394_ARM_WRITE | RAW1394_ARM_LOCK,
348                            RAW1394_ARM_READ | RAW1394_ARM_WRITE | RAW1394_ARM_LOCK,
349                            0);
350
351     printf(" adding (%p) as arm handler\n", test_arm);
352
353     if (!m_service->registerARMHandler(test_arm)) {
354         printf("  failed\n");
355     }
356
357     addr =  m_service->findFreeARMBlock(0x0000FFFFE0000000ULL, 4, 4 );
358
359     Ieee1394Service::ARMHandler *test_arm2 = new Ieee1394Service::ARMHandler(*m_service, addr,
360                             4,
361                             RAW1394_ARM_READ | RAW1394_ARM_WRITE | RAW1394_ARM_LOCK,
362                             RAW1394_ARM_READ | RAW1394_ARM_WRITE | RAW1394_ARM_LOCK,
363                             0);
364
365     printf(" adding (%p) as arm handler\n", test_arm2);
366
367     if (!m_service->registerARMHandler(test_arm2)) {
368         printf("  failed\n");
369     }
370
371     CtrThread *thread_runners[NB_THREADS];
372     Thread* threads[NB_THREADS];
373     for (i=0; i < NB_THREADS; i++) {
374         thread_runners[i] = new CtrThread(m_service);
375         if (thread_runners[i] == NULL) {
376             debugError("could not create thread runner %d\n", i);
377             exit(-1);
378         }
379         threads[i] = new PosixThread(thread_runners[i], THREAD_RT, THREAD_PRIO, PTHREAD_CANCEL_DEFERRED);
380         if (threads[i] == NULL) {
381             debugError("could not create thread %d\n", i);
382             exit(-1);
383         }
384     }
385    
386     for (i=0; i < NB_THREADS; i++) {
387         threads[i]->Start();
388     }
389
390     int cnt=0;
391     while(run) {
392         cnt++;
393         debugOutput(DEBUG_LEVEL_NORMAL, "%08d: (max: %6d, min: %6d)\n", cnt, max_diff, min_diff);
394         m_service->show();
395         max_diff = -999999;
396         min_diff = 999999;
397        
398         for (i=0; i < NB_THREADS; i++) {
399             debugOutput(DEBUG_LEVEL_NORMAL, "%2d: avg: %6f\n", i,  thread_runners[i]->avg_diff);
400             thread_runners[i]->m_reset_avg = 1;
401         }
402        
403        
404         sleep(DISP_CYCLE_SLEEP_SECS);
405     }
406
407     for (i=0; i < NB_THREADS; i++) {
408         threads[i]->Stop();
409     }
410
411     for (i=0; i < NB_THREADS; i++) {
412         delete threads[i];
413         delete thread_runners[i];
414     }
415
416     delete m_service;
417     delete test_busreset;
418     delete test_arm;
419     delete test_arm2;
420
421     printf("Bye...\n");
422
423     return EXIT_SUCCESS;
424 }
Note: See TracBrowser for help on using the browser.