root/trunk/libfreebob/src/libstreaming/IsoHandler.cpp

Revision 360, 27.8 kB (checked in by pieterpalmers, 16 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 /* $Id$ */
2
3 /*
4  *   FreeBob Streaming API
5  *   FreeBob = Firewire (pro-)audio for linux
6  *
7  *   http://freebob.sf.net
8  *
9  *   Copyright (C) 2006 Pieter Palmers <pieterpalmers@users.sourceforge.net>
10  *
11  *   This program is free software {} you can redistribute it and/or modify
12  *   it under the terms of the GNU General Public License as published by
13  *   the Free Software Foundation {} either version 2 of the License, or
14  *   (at your option) any later version.
15  *
16  *   This program is distributed in the hope that it will be useful,
17  *   but WITHOUT ANY WARRANTY {} without even the implied warranty of
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *   GNU General Public License for more details.
20  *
21  *   You should have received a copy of the GNU General Public License
22  *   along with this program {} if not, write to the Free Software
23  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  *
25  *
26  *
27  */
28
29 #include "IsoHandler.h"
30 #include "IsoStream.h"
31 #include "cyclecounter.h"
32
33 #include "libutil/Time.h"
34 #include "libutil/TimeSource.h"
35 #include "libutil/SystemTimeSource.h"
36
37 #include <errno.h>
38 #include <netinet/in.h>
39 #include <assert.h>
40 #include <unistd.h>
41
42 #include <iostream>
43 using namespace std;
44
45
46 #define CC_SLEEP_TIME_AFTER_UPDATE     100
47 #define CC_SLEEP_TIME_AFTER_FAILURE     10
48 #define CC_DLL_COEFF     ((0.01)*((float)(CC_SLEEP_TIME_AFTER_UPDATE/1000.0)))
49
50 #define CC_MAX_RATE_ERROR           (2/100.0)
51 #define CC_INIT_MAX_TRIES 10
52
53
54 namespace FreebobStreaming
55 {
56
57 IMPL_DEBUG_MODULE( IsoHandler, IsoHandler, DEBUG_LEVEL_NORMAL );
58
59 /* the C callbacks */
60 enum raw1394_iso_disposition
61 IsoXmitHandler::iso_transmit_handler(raw1394handle_t handle,
62                 unsigned char *data, unsigned int *length,
63                 unsigned char *tag, unsigned char *sy,
64                 int cycle, unsigned int dropped) {
65
66         IsoXmitHandler *xmitHandler=static_cast<IsoXmitHandler *>(raw1394_get_userdata(handle));
67         assert(xmitHandler);
68
69         return xmitHandler->getPacket(data, length, tag, sy, cycle, dropped);
70 }
71
72 enum raw1394_iso_disposition
73 IsoRecvHandler::iso_receive_handler(raw1394handle_t handle, unsigned char *data,
74                                                 unsigned int length, unsigned char channel,
75                                                 unsigned char tag, unsigned char sy, unsigned int cycle,
76                                                 unsigned int dropped) {
77
78         IsoRecvHandler *recvHandler=static_cast<IsoRecvHandler *>(raw1394_get_userdata(handle));
79         assert(recvHandler);
80
81         return recvHandler->putPacket(data, length, channel, tag, sy, cycle, dropped);
82 }
83
84 int IsoHandler::busreset_handler(raw1394handle_t handle, unsigned int generation)
85 {       
86         debugOutput( DEBUG_LEVEL_VERBOSE, "Busreset happened, generation %d...\n", generation);
87
88         IsoHandler *handler=static_cast<IsoHandler *>(raw1394_get_userdata(handle));
89         assert(handler);
90         return handler->handleBusReset(generation);
91 }
92
93
94 /* Base class implementation */
95 IsoHandler::IsoHandler(int port)
96    : TimeSource(), m_handle(0), m_handle_util(0), m_port(port),
97    m_buf_packets(400), m_max_packet_size(1024), m_irq_interval(-1),
98    m_cyclecounter_ticks(0), m_lastmeas_usecs(0), m_ticks_per_usec(24.576),
99    m_ticks_per_usec_dll_err2(0),
100    m_packetcount(0), m_dropped(0), m_Client(0)
101 {
102     InitTime();
103     m_TimeSource=new FreebobUtil::SystemTimeSource();
104 }
105
106 IsoHandler::IsoHandler(int port, unsigned int buf_packets, unsigned int max_packet_size, int irq)
107    : TimeSource(), m_handle(0), m_port(port),
108    m_buf_packets(buf_packets), m_max_packet_size( max_packet_size),
109    m_irq_interval(irq),
110    m_cyclecounter_ticks(0), m_lastmeas_usecs(0), m_ticks_per_usec(24.576),
111    m_ticks_per_usec_dll_err2(0),
112    m_packetcount(0), m_dropped(0), m_Client(0)
113 {
114     InitTime();
115     m_TimeSource=new FreebobUtil::SystemTimeSource();
116 }
117
118 IsoHandler::~IsoHandler() {
119     if(m_handle) {
120         stop();
121         raw1394_destroy_handle(m_handle);
122     }
123     if(m_handle_util) raw1394_destroy_handle(m_handle_util);
124    
125     delete m_TimeSource;
126 }
127
128 bool
129 IsoHandler::init()
130 {
131         debugOutput( DEBUG_LEVEL_VERBOSE, "IsoHandler (%p) enter...\n",this);
132
133         m_handle = raw1394_new_handle_on_port( m_port );
134         if ( !m_handle ) {
135                 if ( !errno ) {
136                         cerr << "libraw1394 not compatible" << endl;
137                 } else {
138                         perror( "IsoHandler::Initialize: Could not get 1394 handle" );
139                         cerr << "Is ieee1394 and raw1394 driver loaded?" << endl;
140                 }
141                 return false;
142         }
143         raw1394_set_userdata(m_handle, static_cast<void *>(this));
144        
145         // a second handle for utility stuff
146         m_handle_util = raw1394_new_handle_on_port( m_port );
147         if ( !m_handle_util ) {
148                 if ( !errno ) {
149                         cerr << "libraw1394 not compatible" << endl;
150                 } else {
151                         perror( "IsoHandler::Initialize: Could not get 1394 handle" );
152                         cerr << "Is ieee1394 and raw1394 driver loaded?" << endl;
153                 }
154                 return false;
155         }
156        
157         raw1394_set_userdata(m_handle_util, static_cast<void *>(this));
158        
159         if(raw1394_busreset_notify (m_handle, RAW1394_NOTIFY_ON)) {
160                 debugWarning("Could not enable busreset notification.\n");
161                 debugWarning(" Error message: %s\n",strerror(errno));
162         }
163        
164         raw1394_set_bus_reset_handler(m_handle, busreset_handler);
165
166     // initialize the local timesource
167     m_TimeSource_NbCycleWraps=0;
168     quadlet_t buf=0;
169     unsigned int new_counter;
170    
171     raw1394_read(m_handle_util, raw1394_get_local_id(m_handle_util),
172         CSR_REGISTER_BASE | CSR_CYCLE_TIME, 4, &buf);
173    
174     new_counter= ntohl(buf) & 0xFFFFFFFF;
175     m_TimeSource_LastSecs=CYCLE_COUNTER_GET_SECS(new_counter);
176
177     // update the cycle counter value for initial value
178     initCycleCounter();
179
180         return true;
181 }
182
183 bool
184 IsoHandler::setSyncMaster(FreebobUtil::TimeSource *t)
185 {
186     m_TimeSource=t;
187    
188     // update the cycle counter value for initial value
189     initCycleCounter();
190    
191     return true;
192 }
193
194 bool IsoHandler::stop()
195 {
196         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
197         raw1394_iso_stop(m_handle);
198         return true;
199 }
200
201 /**
202  * Bus reset handler
203  *
204  * @return ?
205  */
206  
207 int IsoHandler::handleBusReset(unsigned int generation) {
208         debugOutput( DEBUG_LEVEL_VERBOSE, "bus reset...\n");
209        
210         // as busreset can elect a new cycle master,
211         // we need to re-initialize our timing code
212     initCycleCounter();
213    
214         return 0;
215 }
216
217 /**
218  * Returns the current value of the cycle counter (in ticks)
219  *
220  * @return the current value of the cycle counter (in ticks)
221  */
222
223 unsigned int IsoHandler::getCycleCounter() {
224     // calculate the cycle counter based upon the current time
225     // and the estimated tick rate
226     freebob_microsecs_t now=m_TimeSource->getCurrentTimeAsUsecs();
227    
228     // linear interpolation
229     int delta_usecs=now-m_lastmeas_usecs;
230
231     float offset=m_ticks_per_usec * ((float)delta_usecs);
232    
233     unsigned int pred_ticks=m_cyclecounter_ticks+(unsigned int)offset;
234    
235     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Get CC: d_usecs=%d, offset=%f, cc_ticks=%lu, pred_ticks=%lu\n",
236       delta_usecs, offset, m_cyclecounter_ticks,pred_ticks
237       );
238      
239     // if we need to wrap, do it
240     if (pred_ticks > TICKS_PER_SECOND * 128) {
241         pred_ticks -= TICKS_PER_SECOND * 128;
242     }
243    
244     return pred_ticks;
245 }
246
247 bool IsoHandler::updateCycleCounter() {
248     quadlet_t buf=0;
249    
250     freebob_microsecs_t prev_usecs=m_lastmeas_usecs;
251     unsigned int prev_ticks=m_cyclecounter_ticks;
252    
253     freebob_microsecs_t new_usecs;
254     unsigned int new_ticks;
255     unsigned int new_counter;
256    
257     /* To estimate the cycle counter, we implement a
258        DLL based routine, that maps the cycle counter
259        on the system clock.
260        
261        For more info, refer to:
262         "Using a DLL to filter time"
263         Fons Adriaensen
264        
265         Can be found at:
266         http://users.skynet.be/solaris/linuxaudio/downloads/usingdll.pdf
267         or maybe at:
268         http://www.kokkinizita.net/linuxaudio
269    
270         Basically what we do is estimate the next point (T1,CC1_est)
271         based upon the previous point (T0, CC0) and the estimated rate (R).
272         Then we compare our estimation with the measured cycle counter
273         at T1 (=CC1_meas). We then calculate the estimation error on R:
274         err=(CC1_meas-CC0)/(T1-T2) - (CC1_est-CC0)/(T1-T2)
275         and try to minimize this on average (DLL)
276        
277         Note that in order to have a contignous mapping, we should
278         update CC0<=CC1_est instead of CC0<=CC1_meas. The measurement
279         serves only to correct the error 'on average'.
280        
281         In the code, the following variable names are used:
282         T0=prev_usecs
283         T1=next_usecs
284        
285         CC0=prev_ticks
286         CC1_est=est_ticks
287         CC1_meas=meas_ticks
288        
289      */
290    
291     // normally we should be able to use the same handle
292     // because it is not iterated on by any other stuff
293     // but I'm not sure
294     raw1394_read(m_handle_util, raw1394_get_local_id(m_handle_util),
295         CSR_REGISTER_BASE | CSR_CYCLE_TIME, 4, &buf);
296     new_usecs=m_TimeSource->getCurrentTimeAsUsecs();
297    
298     new_counter= ntohl(buf) & 0xFFFFFFFF;
299     new_ticks=CYCLE_COUNTER_TO_TICKS(new_counter);
300    
301     // the difference in system time
302     int delta_usecs=new_usecs-prev_usecs;
303     // this cannot be 0, because m_TimeSource->getCurrentTimeAsUsecs should
304     // never return the same value (maybe in future terrahz processors?)
305     assert(delta_usecs);
306    
307     // the measured cycle counter difference
308     unsigned int delta_ticks_meas;
309     if (new_ticks > prev_ticks) {
310         delta_ticks_meas=new_ticks - prev_ticks;
311     } else { // wraparound
312         delta_ticks_meas=CYCLE_COUNTER_UNWRAP_TICKS(new_ticks) - prev_ticks;
313     }
314    
315     // the estimated cycle counter difference
316     unsigned int delta_ticks_est=(unsigned int)(m_ticks_per_usec * ((float)delta_usecs));
317    
318     // the measured & estimated rate
319     float rate_meas=((float)delta_ticks_meas/(float)delta_usecs);
320     float rate_est=((float)m_ticks_per_usec);
321    
322     // these make sure we don't update when the measurement is
323     // bad. We know the nominal rate, and it can't be that far
324     // off. The thing is that there is a problem in measuring
325     // both usecs and ticks at the same time (no provision in
326     // the kernel.
327     // We know that there are some tolerances on both
328     // the system clock and the firewire clock such that the
329     // actual difference is rather small. So we discard values
330     // that are too far from the nominal rate.
331     // Otherwise the DLL has to have a very low bandwidth, in
332     // order not to be desturbed too much by these bad measurements
333     // resulting in very slow locking.
334    
335     if (   (rate_meas < 24.576*(1.0+CC_MAX_RATE_ERROR))
336         && (rate_meas > 24.576*(1.0-CC_MAX_RATE_ERROR))) {
337
338 #ifdef DEBUG
339
340         int diff=(int)delta_ticks_est;
341        
342         // calculate the difference in predicted ticks and
343         // measured ticks
344         diff -= delta_ticks_meas;
345        
346        
347         if (diff > 24000 || diff < -24000) { // approx +/-1 msec error
348             debugOutput(DEBUG_LEVEL_VERBOSE,"Bad pred (%p): diff=%d, dt_est=%u, dt_meas=%u, d=%dus, err=%fus\n", this,
349                 diff, delta_ticks_est, delta_ticks_meas, delta_usecs, (((float)diff)/24.576)
350                 );
351         } else {
352             debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Good pred: diff=%d, dt_est=%u, dt_meas=%u, d=%dus, err=%fus\n",
353                 diff, delta_ticks_est, delta_ticks_meas, delta_usecs, (((float)diff)/24.576)
354                 );
355         }
356 #endif
357         // DLL the error to obtain the rate.
358         // (note: the DLL makes the error=0)
359         // only update the DLL if the rate is within 10% of the expected
360         // rate
361         float err=rate_meas-rate_est;
362        
363         // 2nd order DLL update
364 //         const float w=6.28*0.0001;
365 //         const float b=w*1.45;
366 //         const float c=w*w;
367 //         
368 //         m_ticks_per_usec += b*err + m_ticks_per_usec_dll_err2;
369 //         m_ticks_per_usec_dll_err2 += c * err;
370
371         // first order DLL update
372          m_ticks_per_usec += CC_DLL_COEFF*err;
373    
374         if (   (m_ticks_per_usec > 24.576*(1.0+CC_MAX_RATE_ERROR))
375             || (m_ticks_per_usec < 24.576*(1.0-CC_MAX_RATE_ERROR))) {
376             debugOutput(DEBUG_LEVEL_VERBOSE, "Warning: DLL ticks/usec near clipping (%8.4f)\n",
377                         m_ticks_per_usec);
378         }
379        
380         // update the internal values
381         // note: the next cyclecounter point is
382         //       the estimated one, not the measured one!
383         m_cyclecounter_ticks += delta_ticks_est;
384         // if we need to wrap, do it
385         if (m_cyclecounter_ticks > TICKS_PER_SECOND * 128) {
386             m_cyclecounter_ticks -= TICKS_PER_SECOND * 128;
387         }
388            
389         m_lastmeas_usecs = new_usecs;
390
391         debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"U TS: %10u -> %10u, d=%7uus, dt_est=%7u,  dt_meas=%7u, erate=%6.4f, mrate=%6f\n",
392               prev_ticks, m_cyclecounter_ticks, delta_usecs,
393               delta_ticks_est, delta_ticks_meas, m_ticks_per_usec, rate_meas
394               );
395
396         // the estimate is good
397         return true;
398     } else {
399         debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"U TS: Not updating, rate out of range (%6.4f)\n",
400               rate_meas
401               );
402         return false;
403
404     }
405 }
406
407 void IsoHandler::initCycleCounter() {
408     quadlet_t buf=0;
409
410     freebob_microsecs_t prev_usecs;
411     unsigned int prev_ticks;
412     unsigned int prev_counter;
413    
414     freebob_microsecs_t new_usecs;
415     unsigned int new_ticks;
416     unsigned int new_counter;
417    
418     float rate=0.0;
419    
420     unsigned int try_cnt=0;
421    
422     // make sure that we start with a decent rate,
423     // meaning that we want two successive (usecs,ticks)
424     // points that make sense.
425    
426     while ( (try_cnt++ < CC_INIT_MAX_TRIES) &&
427            (   (rate > 24.576*(1.0+CC_MAX_RATE_ERROR))
428            || (rate < 24.576*(1.0-CC_MAX_RATE_ERROR)))) {
429            
430         // normally we should be able to use the same handle
431         // because it is not iterated on by any other stuff
432         // but I'm not sure
433         raw1394_read(m_handle_util, raw1394_get_local_id(m_handle_util),
434             CSR_REGISTER_BASE | CSR_CYCLE_TIME, 4, &buf);
435         prev_usecs=m_TimeSource->getCurrentTimeAsUsecs();
436        
437         prev_counter= ntohl(buf) & 0xFFFFFFFF;
438         prev_ticks=CYCLE_COUNTER_TO_TICKS(prev_counter);
439        
440         usleep(CC_SLEEP_TIME_AFTER_UPDATE);
441        
442         // normally we should be able to use the same handle
443         // because it is not iterated on by any other stuff
444         // but I'm not sure
445         raw1394_read(m_handle_util, raw1394_get_local_id(m_handle_util),
446             CSR_REGISTER_BASE | CSR_CYCLE_TIME, 4, &buf);
447         new_usecs=m_TimeSource->getCurrentTimeAsUsecs();
448        
449         new_counter= ntohl(buf) & 0xFFFFFFFF;
450         new_ticks=CYCLE_COUNTER_TO_TICKS(new_counter);
451        
452         unsigned int delta_ticks;
453        
454         if (new_ticks > prev_ticks) {
455             delta_ticks=new_ticks - prev_ticks;
456         } else { // wraparound
457             delta_ticks=CYCLE_COUNTER_UNWRAP_TICKS(new_ticks) - prev_ticks;
458         }
459        
460         int delta_usecs=new_usecs-prev_usecs;
461        
462         // this cannot be 0, because m_TimeSource->getCurrentTimeAsUsecs should
463         // never return the same value (maybe in future terrahz processors?)
464         assert(delta_usecs);
465        
466         rate=((float)delta_ticks/(float)delta_usecs);
467        
468         // update the internal values
469         m_cyclecounter_ticks=new_ticks;
470         m_lastmeas_usecs=new_usecs;
471        
472         debugOutput(DEBUG_LEVEL_VERBOSE,"Try %d: rate=%6.4f\n",
473             try_cnt,rate
474             );
475
476     }
477    
478     // this is not fatal, the DLL will eventually correct this
479     if(try_cnt == CC_INIT_MAX_TRIES) {
480         debugWarning("Failed to properly initialize cycle counter...\n");
481     }
482    
483     // initialize this to the nominal value
484     m_ticks_per_usec = 24.576;
485     m_ticks_per_usec_dll_err2 = 0;
486    
487 }
488
489 void IsoHandler::dumpInfo()
490 {
491
492         int channel=-1;
493         if (m_Client) channel=m_Client->getChannel();
494
495         debugOutputShort( DEBUG_LEVEL_NORMAL, "  Handler type    : %s\n",
496              (this->getType()==EHT_Receive ? "Receive" : "Transmit"));
497         debugOutputShort( DEBUG_LEVEL_NORMAL, "  Port, Channel  : %2d, %2d\n",
498              m_port, channel);
499         debugOutputShort( DEBUG_LEVEL_NORMAL, "  Packet count   : %10d (%5d dropped)\n",
500              this->getPacketCount(), this->getDroppedCount());
501     #ifdef DEBUG
502     unsigned int cc=this->getCycleCounter();
503         debugOutputShort( DEBUG_LEVEL_NORMAL, "  Cycle counter  : %10lu (%03us, %04ucycles, %04uticks)\n",
504              cc,TICKS_TO_SECS(cc),TICKS_TO_CYCLES(cc),TICKS_TO_OFFSET(cc));
505         #endif
506         debugOutputShort( DEBUG_LEVEL_NORMAL, "  Ticks/usec     : %8.6f (dll2: %8.6e)\n\n",
507              this->getTicksPerUsec(), m_ticks_per_usec_dll_err2);
508
509 };
510
511 void IsoHandler::setVerboseLevel(int l)
512 {
513         setDebugLevel(l);
514 }
515
516 bool IsoHandler::registerStream(IsoStream *stream)
517 {
518         assert(stream);
519         debugOutput( DEBUG_LEVEL_VERBOSE, "registering stream (%p)\n", stream);
520
521         if (m_Client) {
522                 debugFatal( "Generic IsoHandlers can have only one client\n"); 
523                 return false;
524         }
525
526         m_Client=stream;
527
528         m_Client->setHandler(this);
529
530         return true;
531
532 }
533
534 bool IsoHandler::unregisterStream(IsoStream *stream)
535 {
536         assert(stream);
537         debugOutput( DEBUG_LEVEL_VERBOSE, "unregistering stream (%p)\n", stream);
538
539         if(stream != m_Client) {
540                 debugFatal( "no client registered\n"); 
541                 return false;
542         }
543
544         m_Client->clearHandler();
545        
546         m_Client=0;
547         return true;
548
549 }
550
551 /* The timesource interface */
552 freebob_microsecs_t IsoHandler::getCurrentTime() {
553     quadlet_t buf=0;
554     unsigned int new_counter;
555    
556     raw1394_read(m_handle_util, raw1394_get_local_id(m_handle_util),
557         CSR_REGISTER_BASE | CSR_CYCLE_TIME, 4, &buf);
558    
559     new_counter= ntohl(buf) & 0xFFFFFFFF;
560        
561     // this assumes that it never happens that there are more than 2
562     // minutes between calls
563     if (CYCLE_COUNTER_GET_SECS(new_counter) < m_TimeSource_LastSecs) {
564         m_TimeSource_NbCycleWraps++;
565     }
566    
567     freebob_microsecs_t ticks=m_TimeSource_NbCycleWraps * 128 * TICKS_PER_SECOND
568             + CYCLE_COUNTER_TO_TICKS(new_counter);
569    
570     m_TimeSource_LastSecs=CYCLE_COUNTER_GET_SECS(new_counter);
571    
572     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Wraps=%4u, LastSecs=%3u, nowSecs=%3u, ticks=%10u\n",
573               m_TimeSource_NbCycleWraps, m_TimeSource_LastSecs,
574               CYCLE_COUNTER_GET_SECS(new_counter), ticks
575               );
576              
577     return  ticks;
578 }
579
580 freebob_microsecs_t IsoHandler::getCurrentTimeAsUsecs() {
581     float tmp=getCurrentTime();
582     float tmp2 = tmp * USECS_PER_TICK;
583     freebob_microsecs_t retval=(freebob_microsecs_t)tmp2;
584    
585     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"tmp=%f, tmp2=%f, retval=%u\n",
586               tmp, tmp2,retval
587               );
588    
589     return retval;
590 }
591
592
593
594 /* Child class implementations */
595
596 IsoRecvHandler::IsoRecvHandler(int port)
597                 : IsoHandler(port)
598 {
599         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
600 }
601 IsoRecvHandler::IsoRecvHandler(int port, unsigned int buf_packets,
602                                unsigned int max_packet_size, int irq)
603                 : IsoHandler(port, buf_packets,max_packet_size,irq)
604 {
605         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
606
607 }
608 IsoRecvHandler::~IsoRecvHandler()
609 {
610 // Don't call until libraw1394's raw1394_new_handle() function has been
611 // fixed to correctly initialise the iso_packet_infos field.  Bug is
612 // confirmed present in libraw1394 1.2.1.  In any case,
613 // raw1394_destroy_handle() will do any iso system shutdown required.
614 //      raw1394_iso_shutdown(m_handle);
615         raw1394_destroy_handle(m_handle);
616         m_handle = NULL;
617 }
618
619 bool
620 IsoRecvHandler::init() {
621         debugOutput( DEBUG_LEVEL_VERBOSE, "init recv handler %p\n",this);
622
623         if(!(IsoHandler::init())) {
624                 return false;
625         }
626         return true;
627
628 }
629
630 enum raw1394_iso_disposition IsoRecvHandler::putPacket(unsigned char *data, unsigned int length,
631                               unsigned char channel, unsigned char tag, unsigned char sy,
632                                   unsigned int cycle, unsigned int dropped) {
633
634         debugOutput( DEBUG_LEVEL_VERY_VERBOSE,
635                      "received packet: length=%d, channel=%d, cycle=%d\n",
636                      length, channel, cycle );
637         m_packetcount++;
638         m_dropped+=dropped;
639
640         if(m_Client) {
641                 return m_Client->putPacket(data, length, channel, tag, sy, cycle, dropped);
642         }
643        
644         return RAW1394_ISO_OK;
645 }
646
647 bool IsoRecvHandler::prepare()
648 {
649 // Don't call until libraw1394's raw1394_new_handle() function has been
650 // fixed to correctly initialise the iso_packet_infos field.  Bug is
651 // confirmed present in libraw1394 1.2.1.
652 //      raw1394_iso_shutdown(m_handle);
653        
654         debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing iso receive handler (%p)\n",this);
655         debugOutput( DEBUG_LEVEL_VERBOSE, " Buffers         : %d \n",m_buf_packets);
656         debugOutput( DEBUG_LEVEL_VERBOSE, " Max Packet size : %d \n",m_max_packet_size);
657         debugOutput( DEBUG_LEVEL_VERBOSE, " Channel         : %d \n",m_Client->getChannel());
658         debugOutput( DEBUG_LEVEL_VERBOSE, " Irq interval    : %d \n",m_irq_interval);
659
660         if(raw1394_iso_recv_init(m_handle,   iso_receive_handler,
661                                          m_buf_packets,
662                                          m_max_packet_size,
663                                              m_Client->getChannel(),
664                                              RAW1394_DMA_BUFFERFILL,
665                                          m_irq_interval)) {
666                 debugFatal("Could not do receive initialisation!\n" );
667                 debugFatal("  %s\n",strerror(errno));
668
669                 return false;
670         }
671         return true;
672 }
673
674 bool IsoRecvHandler::start(int cycle)
675 {
676         debugOutput( DEBUG_LEVEL_VERBOSE, "start on cycle %d\n", cycle);
677        
678         if(raw1394_iso_recv_start(m_handle, cycle, -1, 0)) {
679                 debugFatal("Could not start receive handler (%s)\n",strerror(errno));
680                 return false;
681         }
682         return true;
683 }
684
685 int IsoRecvHandler::handleBusReset(unsigned int generation) {
686         debugOutput( DEBUG_LEVEL_VERBOSE, "handle bus reset...\n");
687        
688         //TODO: implement busreset
689        
690         // pass on the busreset signal
691         if(IsoHandler::handleBusReset(generation)) {
692                 return -1;
693         }
694         return 0;
695 }
696
697 /* ----------------- XMIT --------------- */
698
699 IsoXmitHandler::IsoXmitHandler(int port)
700                 : IsoHandler(port), m_prebuffers(0)
701 {
702         debugOutput( DEBUG_LEVEL_VERBOSE, "IsoXmitHandler enter...\n");
703
704 }
705 IsoXmitHandler::IsoXmitHandler(int port, unsigned int buf_packets,
706                                unsigned int max_packet_size, int irq)
707                 : IsoHandler(port, buf_packets, max_packet_size,irq),
708                   m_speed(RAW1394_ISO_SPEED_400), m_prebuffers(0)
709 {
710         debugOutput( DEBUG_LEVEL_VERBOSE, "IsoXmitHandler enter...\n");
711
712 }
713 IsoXmitHandler::IsoXmitHandler(int port, unsigned int buf_packets,
714                                unsigned int max_packet_size, int irq,
715                                enum raw1394_iso_speed speed)
716                 : IsoHandler(port, buf_packets,max_packet_size,irq),
717                   m_speed(speed), m_prebuffers(0)
718 {
719         debugOutput( DEBUG_LEVEL_VERBOSE, "IsoXmitHandler enter...\n");
720
721 }
722
723 IsoXmitHandler::~IsoXmitHandler()
724 {
725 // Don't call until libraw1394's raw1394_new_handle() function has been
726 // fixed to correctly initialise the iso_packet_infos field.  Bug is
727 // confirmed present in libraw1394 1.2.1.  In any case,
728 // raw1394_destroy_handle() will do any iso system shutdown required.
729 //      raw1394_iso_shutdown(m_handle);
730         raw1394_destroy_handle(m_handle);
731         m_handle = NULL;
732 }
733
734 bool
735 IsoXmitHandler::init() {
736
737         debugOutput( DEBUG_LEVEL_VERBOSE, "init xmit handler %p\n",this);
738
739         if(!(IsoHandler::init())) {
740                 return false;
741         }
742
743         return true;
744
745 }
746
747 enum raw1394_iso_disposition IsoXmitHandler::getPacket(unsigned char *data, unsigned int *length,
748                               unsigned char *tag, unsigned char *sy,
749                               int cycle, unsigned int dropped) {
750
751         debugOutput( DEBUG_LEVEL_VERY_VERBOSE,
752                      "sending packet: length=%d, cycle=%d\n",
753                      *length, cycle );
754         m_packetcount++;
755         m_dropped+=dropped;
756
757         if(m_Client) {
758         return m_Client->getPacket(data, length, tag, sy, cycle, dropped, m_max_packet_size);
759         }
760        
761         return RAW1394_ISO_OK;
762 }
763
764 bool IsoXmitHandler::prepare()
765 {
766         debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing iso transmit handler (%p, client=%p)\n",this,m_Client);
767        
768 //      raw1394_iso_shutdown(m_handle);
769         debugOutput( DEBUG_LEVEL_VERBOSE, " Buffers         : %d \n",m_buf_packets);
770         debugOutput( DEBUG_LEVEL_VERBOSE, " Max Packet size : %d \n",m_max_packet_size);
771         debugOutput( DEBUG_LEVEL_VERBOSE, " Channel         : %d \n",m_Client->getChannel());
772         debugOutput( DEBUG_LEVEL_VERBOSE, " Speed           : %d \n",m_speed);
773         debugOutput( DEBUG_LEVEL_VERBOSE, " Irq interval    : %d \n",m_irq_interval);
774
775         if(raw1394_iso_xmit_init(m_handle,
776                              iso_transmit_handler,
777                              m_buf_packets,
778                              m_max_packet_size,
779                                  m_Client->getChannel(),
780                                  m_speed,
781                              m_irq_interval)) {
782                 debugFatal("Could not do xmit initialisation!\n" );
783
784                 return false;
785         }
786
787         return true;
788 }
789
790 bool IsoXmitHandler::start(int cycle)
791 {
792         debugOutput( DEBUG_LEVEL_VERBOSE, "start on cycle %d\n", cycle);
793         if(raw1394_iso_xmit_start(m_handle, cycle, m_prebuffers)) {
794                 debugFatal("Could not start xmit handler (%s)\n",strerror(errno));
795                 return false;
796         }
797         return true;
798 }
799
800 int IsoXmitHandler::handleBusReset(unsigned int generation) {
801         debugOutput( DEBUG_LEVEL_VERBOSE, "bus reset...\n");
802         //TODO: implement busreset
803        
804         // pass on the busreset signal
805         if(IsoHandler::handleBusReset(generation)) {
806                 return -1;
807         }
808        
809         return 0;
810 }
811
812 }
813
814 /* multichannel receive  */
815 #if 0
816 IsoRecvHandler::IsoRecvHandler(int port)
817                 : IsoHandler(port)
818 {
819         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
820 }
821 IsoRecvHandler::IsoRecvHandler(int port, unsigned int buf_packets,
822                                unsigned int max_packet_size, int irq)
823                 : IsoHandler(port, buf_packets,max_packet_size,irq)
824 {
825         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
826
827 }
828 IsoRecvHandler::~IsoRecvHandler()
829 {
830 // Don't call until libraw1394's raw1394_new_handle() function has been
831 // fixed to correctly initialise the iso_packet_infos field.  Bug is
832 // confirmed present in libraw1394 1.2.1.  In any case,
833 // raw1394_destroy_handle() (in the base class destructor) will do any iso
834 // system shutdown required.
835         raw1394_iso_shutdown(m_handle);
836
837 }
838
839 bool
840 IsoRecvHandler::initialize() {
841         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
842
843         IsoHandler *base=static_cast<IsoHandler *>(this);
844
845         if(!(base->initialize())) {
846                 return false;
847         }
848
849         raw1394_set_userdata(m_handle, static_cast<void *>(this));
850
851         if(raw1394_iso_multichannel_recv_init(m_handle,
852                                          iso_receive_handler,
853                                          m_buf_packets,
854                                          m_max_packet_size,
855                                          m_irq_interval)) {
856                 debugFatal("Could not do multichannel receive initialisation!\n" );
857
858                 return false;
859         }
860
861         return true;
862
863 }
864
865 enum raw1394_iso_disposition IsoRecvHandler::putPacket(unsigned char *data, unsigned int length,
866                               unsigned char channel, unsigned char tag, unsigned char sy,
867                                   unsigned int cycle, unsigned int dropped) {
868
869         debugOutput( DEBUG_LEVEL_VERY_VERBOSE,
870                      "received packet: length=%d, channel=%d, cycle=%d\n",
871                      length, channel, cycle );
872        
873         return RAW1394_ISO_OK;
874 }
875
876 // an recv handler can have multiple destination IsoStreams
877 // NOTE: this implementation even allows for already registered
878 // streams to be registered again.
879 int IsoRecvHandler::registerStream(IsoRecvStream *stream)
880 {
881         assert(stream);
882         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
883
884         m_Clients.push_back(stream);
885
886         listen(stream->getChannel());
887         return 0;
888
889 }
890
891 int IsoRecvHandler::unregisterStream(IsoRecvStream *stream)
892 {
893         assert(stream);
894         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
895
896     for ( IsoRecvStreamVectorIterator it = m_Clients.begin();
897           it != m_Clients.end();
898           ++it )
899     {
900         IsoRecvStream* s = *it;
901         if ( s == stream ) {
902                         unListen(s->getChannel());
903             m_Clients.erase(it);
904                         return 0;
905         }
906     }
907
908         return -1; //not found
909
910 }
911
912 void IsoRecvHandler::listen(int channel) {
913         int retval;
914         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
915
916         retval=raw1394_iso_recv_listen_channel(m_handle, channel);
917
918 }
919
920 void IsoRecvHandler::unListen(int channel) {
921         int retval;
922         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
923
924         retval=raw1394_iso_recv_unlisten_channel(m_handle, channel);
925
926 }
927
928 int IsoRecvHandler::start(int cycle)
929 {
930         debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
931         return raw1394_iso_recv_start(m_handle, cycle, -1, 0);
932 }
933 #endif
Note: See TracBrowser for help on using the browser.