root/branches/streaming-rework/tests/test-sytmonitor.cpp

Revision 360, 16.5 kB (checked in by pieterpalmers, 17 years ago)

- temporary commit to backup some work

- Started a framework to synchronize IsoHandlers? to

any generic TimeSource?. The idea is to introduce
one overall time reference, and resynchronize all
other timed events to this time source.
This will, on the long run, allow:

  • combining devices on multiple FW busses together,
    as these are not synched by hardware.
  • synchronizing to the system clock
  • synchronizing to any other time source (e.g.
    when implementing a jackd client, i.e. using
    the freebob devices as jackd clients).

- Implemented a realtime safe way to read the cycle

timer for an IsoHandler?. (+ test application)

- Implemented tests/test-sytmonitor:

Monitors 2 or more channels and reports the average
SYT timestamp difference between both.

- Messed around with SYT timestamping for AMDTP. Doesn't

work (yet).

Line 
1 /***************************************************************************
2   Copyright (C) 2005 by Pieter Palmers   *
3                                                                         *
4   This program is free software; you can redistribute it and/or modify  *
5   it under the terms of the GNU General Public License as published by  *
6   the Free Software Foundation; either version 2 of the License, or     *
7   (at your option) any later version.                                   *
8                                                                         *
9   This program is distributed in the hope that it will be useful,       *
10   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12   GNU General Public License for more details.                          *
13                                                                         *
14   You should have received a copy of the GNU General Public License     *
15   along with this program; if not, write to the                         *
16   Free Software Foundation, Inc.,                                       *
17   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
18  ***************************************************************************/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <argp.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <endian.h>
29
30 #include <signal.h>
31 #include "src/debugmodule/debugmodule.h"
32
33 #include <netinet/in.h>
34
35 #include "src/libstreaming/cyclecounter.h"
36
37 #include "src/libstreaming/IsoHandlerManager.h"
38 #include "SytMonitor.h"
39
40 #include "src/libutil/PosixThread.h"
41
42 #include "pthread.h"
43
44 using namespace FreebobStreaming;
45 using namespace FreebobUtil;
46
47 DECLARE_GLOBAL_DEBUG_MODULE;
48 IMPL_GLOBAL_DEBUG_MODULE( FreeBoB, DEBUG_LEVEL_VERBOSE );
49
50 int run;
51 // Program documentation.
52 static char doc[] = "FreeBoB -- SYT monitor application\n\n";
53
54 // A description of the arguments we accept.
55 static char args_doc[] = "PORT1,CHANNEL1 [PORT2,CHANNEL2 [... up to 128 combo's]]";
56
57 struct port_channel_combo {
58     int channel;
59     int port;
60 };
61
62 struct arguments
63 {
64     short silent;
65     short verbose;
66     int   port;
67     int   node_id;
68     bool   realtime;
69     int   rtprio;
70     struct port_channel_combo args[128];
71     int nb_combos;
72 };
73
74 // The options we understand.
75 static struct argp_option options[] = {
76     {"port",     'p',    "nr",    0,  "IEEE1394 Port to use" },
77     {"realtime",     'R',    0,    0,  "Run with realtime scheduling?" },
78     {"realtime-priority",     'r',    "nr",    0,  "Realtime scheduling priority" },
79     { 0 }
80 };
81
82 //-------------------------------------------------------------
83
84 // Parse a single option.
85 static error_t
86 parse_opt( int key, char* arg, struct argp_state* state )
87 {
88     // Get the input argument from `argp_parse', which we
89     // know is a pointer to our arguments structure.
90     struct arguments* arguments = ( struct arguments* ) state->input;
91     char* tail;
92
93     switch (key) {
94         case 'p':
95             if (arg) {
96             arguments->port = strtol( arg, &tail, 0 );
97             if ( errno ) {
98                 fprintf( stderr,  "Could not parse 'port' argument\n" );
99                 return ARGP_ERR_UNKNOWN;
100             }
101             } else {
102             if ( errno ) {
103                 fprintf( stderr, "Could not parse 'port' argumen\n" );
104                 return ARGP_ERR_UNKNOWN;
105             }
106             }
107             break;
108         case 'R':
109         arguments->realtime = true;
110             break;         
111         case 'r':
112             if (arg) {
113             arguments->rtprio = strtol( arg, &tail, 0 );
114             if ( errno ) {
115                 fprintf( stderr,  "Could not parse 'realtime-priority' argument\n" );
116                 return ARGP_ERR_UNKNOWN;
117             }
118             }
119             break;                 
120         case ARGP_KEY_ARG:
121             if (state->arg_num >= 128) {
122             // Too many arguments.
123             argp_usage( state );
124             }
125            
126             if(sscanf( arg, "%d,%d",
127                &arguments->args[state->arg_num].port,
128                &arguments->args[state->arg_num].channel) != 2) {
129            fprintf( stderr,  "Could not parse port-channel specification ('%s')\n", arg);
130                
131             } else {
132             printf("Adding Port %d, Channel %d to list...\n",
133                arguments->args[state->arg_num].port,
134                arguments->args[state->arg_num].channel);
135                arguments->nb_combos++;
136             }
137             break;
138         case ARGP_KEY_END:
139             if (state->arg_num < 1) {
140             // Not enough arguments.
141             argp_usage( state );
142             }
143             break;
144         default:
145             return ARGP_ERR_UNKNOWN;
146     }
147     return 0;
148 }
149
150 // Our argp parser.
151 static struct argp argp = { options, parse_opt, args_doc, doc };
152
153
154 static void sighandler (int sig)
155 {
156         run = 0;
157 }
158
159 int main(int argc, char *argv[])
160 {
161         int target_port=0;
162         int target_channel_1=0;
163         int target_channel_2=0;
164         bool run_realtime=false;
165         int realtime_prio=20;
166         int nb_iter;
167         int i;
168         struct sched_param params;
169        
170         IsoHandlerManager *m_isoManager=NULL;
171     PosixThread * m_isoManagerThread=NULL;
172    
173     SytMonitor *monitors[128];
174     int stream_offset_ticks[128];
175        
176     struct arguments arguments;
177
178     // Default values.
179     arguments.port        = 0;
180     arguments.node_id     = 0;
181     arguments.rtprio      = 20;
182     arguments.realtime    = false;
183     arguments.nb_combos   = 0;
184
185     // Parse our arguments; every option seen by `parse_opt' will
186     // be reflected in `arguments'.
187     if ( argp_parse ( &argp, argc, argv, 0, 0, &arguments ) ) {
188         fprintf( stderr, "Could not parse command line\n" );
189         goto finish;
190     }
191    
192     memset(&stream_offset_ticks,0,sizeof(unsigned int) * 128);
193    
194    
195         run=1;
196        
197         run_realtime=arguments.realtime;
198         realtime_prio=arguments.rtprio;
199
200         signal (SIGINT, sighandler);
201         signal (SIGPIPE, sighandler);
202
203         debugOutput(DEBUG_LEVEL_NORMAL, "Freebob SYT monitor\n");
204        
205         m_isoManager=new IsoHandlerManager();
206        
207         if(!m_isoManager) {
208                 debugOutput(DEBUG_LEVEL_NORMAL, "Could not create IsoHandlerManager\n");
209                 goto finish;
210         }
211        
212         m_isoManager->setVerboseLevel(DEBUG_LEVEL_VERBOSE);
213                
214     // the thread to execute the manager
215         m_isoManagerThread=new PosixThread(
216               m_isoManager,
217               run_realtime, realtime_prio,
218               PTHREAD_CANCEL_DEFERRED);
219              
220         if(!m_isoManagerThread) {
221                 debugOutput(DEBUG_LEVEL_NORMAL, "Could not create iso manager thread\n");
222                 goto finish;
223         }
224        
225         // register monitors
226         for (i=0;i<arguments.nb_combos;i++) {
227         debugOutput(DEBUG_LEVEL_NORMAL, "Registering SytMonitor %d\n",i);
228        
229         // add a stream to the manager so that it has something to do
230         monitors[i]=new SytMonitor(arguments.args[i].port);
231        
232         if (!monitors[i]) {
233             debugOutput(DEBUG_LEVEL_NORMAL, "Could not create SytMonitor %d\n", i);
234             goto finish;
235         }       
236        
237         monitors[i]->setVerboseLevel(DEBUG_LEVEL_VERBOSE);
238        
239         if (!monitors[i]->init()) {
240             debugOutput(DEBUG_LEVEL_NORMAL, "Could not init SytMonitor %d\n", i);
241             goto finish;
242         }
243        
244         monitors[i]->setChannel(arguments.args[i].channel);
245        
246         if(!m_isoManager->registerStream(monitors[i])) {
247             debugOutput(DEBUG_LEVEL_NORMAL, "Could not register SytMonitor %d\n", i);
248             goto finish;
249         }
250     }
251
252
253         debugOutput(DEBUG_LEVEL_NORMAL,   "Preparing IsoHandlerManager...\n");
254         if (!m_isoManager->prepare()) {
255                 debugOutput(DEBUG_LEVEL_NORMAL, "Could not prepare isoManager\n");
256                 goto finish;
257         }
258
259         debugOutput(DEBUG_LEVEL_NORMAL,   "Starting ISO manager sync update thread...\n");
260
261         // start the runner thread
262         m_isoManagerThread->Start();
263
264         debugOutput(DEBUG_LEVEL_NORMAL,   "Starting IsoHandlers...\n");
265         if (!m_isoManager->startHandlers(0)) {
266                 debugOutput(DEBUG_LEVEL_NORMAL, "Could not start handlers...\n");
267                 goto finish;
268         }
269        
270     if (arguments.realtime) {
271         // get rt priority for this thread too.
272         params.sched_priority = arguments.rtprio + 1;
273         if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &params)) {
274             debugWarning("Couldn't set realtime prio for main thread...");
275         }
276     }
277    
278     // do the actual work
279     nb_iter=0;
280         while(run) {
281         debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"--- Iterate ---\n");
282        
283         if(!m_isoManager->iterate()) {
284             debugFatal("Could not iterate the isoManager\n");
285             return false;
286         }
287        
288         debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"--- Process ---\n");
289         // process the cycle info's
290         if (arguments.nb_combos>0) {
291             int master_guard=0;
292             struct cycle_info master_cif;
293            
294             bool advance_master=true;
295            
296             while (advance_master && monitors[0]->readNextCycleInfo(&master_cif)) {
297                 advance_master=true;
298            
299                 master_guard++;
300                 if(master_guard>1000) {
301                     debugWarning("Guard passed on master sync!\n");
302                     break;
303                 }           
304                 // we try to match the packets received on equal cycles
305                
306                 // unwrap the seconds counter
307                 if (master_cif.seconds==0) master_cif.seconds+=128;
308                
309                 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"MASTER: [%2d: %04us %04uc, %04X]\n",
310                     0,master_cif.seconds,master_cif.cycle,master_cif.syt);
311                
312                 for (i=1;i<arguments.nb_combos;i++) {
313                     struct cycle_info cif;
314                     int slave_guard=0;
315                     bool read_slave=monitors[i]->readNextCycleInfo(&cif);
316                    
317                     while(read_slave) {
318                         slave_guard++;
319                         if(slave_guard>1000) {
320                             debugWarning("Guard passed on slave sync %d!\n",i);
321                             break;
322                         }
323                         // unwrap the seconds counter
324                         if (cif.seconds==0) cif.seconds+=128;
325
326                         if(cif.cycle==master_cif.cycle
327                            && cif.seconds==master_cif.seconds) { // this is the one
328                             debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"  GOOD : [%2d: %04us %04uc, %04X]\n",
329                                 i,cif.seconds, cif.cycle,cif.syt);
330                             monitors[i]->consumeNextCycleInfo();
331                            
332                             // we have a match ;)
333                             if ((cif.syt != 0xFFFF) && (master_cif.syt != 0xFFFF)) {
334                                 // detect seconds wraparound
335                                 if ((master_cif.pres_seconds==0) && (cif.pres_seconds==127)) {
336                                     master_cif.pres_ticks += TICKS_PER_SECOND*128;
337                                 }
338                                 if ((master_cif.pres_seconds==127) && (cif.pres_seconds==0)) {
339                                     cif.pres_ticks += TICKS_PER_SECOND*128;
340                                 }
341                                // average out the offset
342                                 int err=(((long)master_cif.pres_ticks) - ((long)cif.pres_ticks));
343                                
344                                 err = err - stream_offset_ticks[i];
345                                
346                                 if(err>50000 || err < -50000) {
347                                     debugOutput(DEBUG_LEVEL_NORMAL,
348                                         " Large Diff: %dticks, delta=%d; avg=%d\n",
349                                         err,(((int)master_cif.pres_ticks) - ((int)cif.pres_ticks)),stream_offset_ticks[i]);
350                                    
351                                     debugOutput(DEBUG_LEVEL_NORMAL,
352                                         "  Master   : %04X -> %10u (%04us %04uc %04ut)\n",
353                                         master_cif.syt, master_cif.pres_ticks,
354                                         master_cif.pres_seconds, master_cif.pres_cycle, master_cif.pres_offset
355                                         );
356                                     debugOutput(DEBUG_LEVEL_NORMAL,
357                                         "             [%04us %04uc, %04X (%02uc %04ut)]\n",
358                                         master_cif.seconds,master_cif.cycle,
359                                         master_cif.syt, CYCLE_COUNTER_GET_CYCLES(master_cif.syt),
360                                         CYCLE_COUNTER_GET_OFFSET(master_cif.syt));
361                                        
362                                     debugOutput(DEBUG_LEVEL_NORMAL,
363                                         "  Current  : %04X -> %10u (%04us %04uc %04ut)\n",
364                                         cif.syt, cif.pres_ticks,
365                                         cif.pres_seconds, cif.pres_cycle, cif.pres_offset
366                                         );
367                                     debugOutput(DEBUG_LEVEL_NORMAL,
368                                         "             [%04us %04uc, %04X (%02uc %04ut)]\n",
369                                         cif.seconds,cif.cycle,
370                                         cif.syt, CYCLE_COUNTER_GET_CYCLES(cif.syt),
371                                         CYCLE_COUNTER_GET_OFFSET(cif.syt));
372                                     debugOutput(DEBUG_LEVEL_NORMAL,"\n");
373                                 }
374                                
375                                 stream_offset_ticks[i] += err/1000;
376                                    
377                                 debugOutput(DEBUG_LEVEL_VERY_VERBOSE," Difference: %dticks\n",
378                                         (((int)master_cif.pres_ticks) - ((int)cif.pres_ticks)));
379                             }
380                            
381                             break;
382                         } else {
383                             if ((cif.seconds < master_cif.seconds) ||
384                                 ((cif.seconds == master_cif.seconds)
385                                  && (cif.cycle < master_cif.cycle))) {
386                                
387                                 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"  LAGS : [%2d: %04us %04uc, %04X]\n",
388                                     i,cif.seconds, cif.cycle,cif.syt);
389                                 // the stream lags behind
390                                
391                                 // advance the read pointer
392                                 // this will always succeed, otherwise we wouldn't be
393                                 // in this while()
394                                 monitors[i]->consumeNextCycleInfo();
395                             } else {
396                                 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"  LEADS: [%2d: %04us %04uc, %04X]\n",
397                                     i,cif.seconds, cif.cycle,cif.syt);
398                            
399                                 // the stream is too far ahead,
400                                 // don't do anything
401                                 break;
402                             }
403                         }
404                         read_slave=monitors[i]->readNextCycleInfo(&cif);
405                     }
406
407                     // detect an empty buffer
408                     if (!read_slave) {
409                         debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"    > No more info's (1)\n");
410                         advance_master=false;
411                     }
412
413                 }
414                 debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE,"\n");
415                 if (advance_master) {
416                     monitors[0]->consumeNextCycleInfo();
417                 }
418             }
419         }
420        
421         // show info every x iterations
422         if ((nb_iter++ % 4000)==0) {
423             m_isoManager->dumpInfo();
424             for (i=0;i<arguments.nb_combos;i++) {
425                 monitors[i]->dumpInfo();
426                 debugOutput(DEBUG_LEVEL_NORMAL,"    ==> Stream offset: %10d ticks\n",stream_offset_ticks[i]);
427             }
428         }
429         }
430
431         debugOutput(DEBUG_LEVEL_NORMAL,   "Stopping handlers...\n");
432         if(!m_isoManager->stopHandlers()) {
433            debugOutput(DEBUG_LEVEL_NORMAL, "Could not stop ISO handlers\n");
434            goto finish;
435         }
436        
437         // stop the sync thread
438         debugOutput(DEBUG_LEVEL_NORMAL,   "Stopping ISO manager sync update thread...\n");
439         m_isoManagerThread->Stop();
440        
441         // unregister monitors
442         for (i=0;i<arguments.nb_combos;i++) {
443         debugOutput(DEBUG_LEVEL_NORMAL, "Unregistering SytMonitor %d\n",i);
444        
445         if(!m_isoManager->unregisterStream(monitors[i])) {
446             debugOutput(DEBUG_LEVEL_NORMAL, "Could not unregister SytMonitor %d\n",i);
447             goto finish;
448             }
449             delete monitors[i];
450     }
451        
452         delete m_isoManagerThread;
453     delete m_isoManager;
454
455 finish:
456         debugOutput(DEBUG_LEVEL_NORMAL, "Bye...\n");
457
458     delete DebugModuleManager::instance();
459        
460   return EXIT_SUCCESS;
461 }
Note: See TracBrowser for help on using the browser.