root/branches/streaming-rework/src/libstreaming/cycletimer.h

Revision 411, 13.2 kB (checked in by pieterpalmers, 16 years ago)

cycletimer.h:
- some extra operations on Ticks (diffTicks & substractTicks)

StreamProcessor?.cpp
AmdtpStreamProcessor?.cpp
MotuStreamProcessor?.cpp:
- Moved the syncDelay to StreamProcessor::getTimeUntilNextPeriodSignalUsecs(). This delay should be the delay between the actual period boundary and the time it is reported to the SPManager. Therefore it's place is not as a buffer offset, but in the calculation of the signalling time.
This makes that the buffer timestamps correspond to 'real' timestamps. These might have to be manipulated by the transmit or receive handles to account for e.g. iso buffering etc..., but at least the timestamps themselves have a well-defined meaning now.

StreamProcessorManager?.cpp:
- The only stream that needs to be running is the sync source stream. It is assumed that the other streams start running in time. 'In time' is currently about 2000 cycles afterwards.

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) 2005,2006,2007 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 /* Definitions and utility macro's to handle the ISO cycle timer */
30
31 #ifndef __CYCLETIMER_H__
32 #define __CYCLETIMER_H__
33
34 #include <inttypes.h>
35 #include "debugmodule/debugmodule.h"
36
37 #define CSR_CYCLE_TIME            0x200
38 #define CSR_REGISTER_BASE  0xfffff0000000ULL
39
40 #define CYCLES_PER_SECOND   8000U
41 #define TICKS_PER_CYCLE     3072U
42 #define TICKS_PER_SECOND    24576000UL
43 #define TICKS_PER_USEC     (24.576000)
44
45 #define USECS_PER_TICK     (1.0/TICKS_PER_USEC)
46 #define USECS_PER_CYCLE    (125U)
47
48 #define CYCLE_TIMER_GET_SECS(x)   ((((x) & 0xFE000000UL) >> 25))
49 #define CYCLE_TIMER_GET_CYCLES(x) ((((x) & 0x01FFF000UL) >> 12))
50 #define CYCLE_TIMER_GET_OFFSET(x)  ((((x) & 0x00000FFFUL)))
51 #define CYCLE_TIMER_TO_TICKS(x) ((CYCLE_TIMER_GET_SECS(x)   * TICKS_PER_SECOND) +\
52                                    (CYCLE_TIMER_GET_CYCLES(x) * TICKS_PER_CYCLE ) +\
53                                    (CYCLE_TIMER_GET_OFFSET(x)            ))
54                                    
55 // non-efficient versions, to be avoided in critical code
56 #define TICKS_TO_SECS(x) ((x)/TICKS_PER_SECOND)
57 #define TICKS_TO_CYCLES(x) (((x)/TICKS_PER_CYCLE) % CYCLES_PER_SECOND)
58 #define TICKS_TO_OFFSET(x) (((x)%TICKS_PER_CYCLE))
59
60 #define TICKS_TO_CYCLE_TIMER(x) (  ((TICKS_TO_SECS(x) & 0x7F) << 25) \
61                                  | ((TICKS_TO_CYCLES(x) & 0x1FFF) << 12) \
62                                  | ((TICKS_TO_OFFSET(x) & 0xFFF)))
63                                  
64 #define TICKS_TO_SYT(x)         (((TICKS_TO_CYCLES(x) & 0xF) << 12) \
65                                  | ((TICKS_TO_OFFSET(x) & 0xFFF)))
66
67 #define CYCLE_TIMER_UNWRAP_TICKS(x) (((uint64_t)(x)) \
68                                        + (127ULL * TICKS_PER_SECOND) \
69                                        + (CYCLES_PER_SECOND * TICKS_PER_CYCLE) \
70                                        + (TICKS_PER_CYCLE) \
71                                       )
72 #define CYCLE_TIMER_WRAP_TICKS(x) ((x % TICKS_PER_SECOND))
73
74 DECLARE_GLOBAL_DEBUG_MODULE;
75
76 /**
77  * @brief Wraps x to the maximum number of ticks
78  *
79  * The input value is wrapped to the maximum value of the cycle
80  * timer, in ticks (128sec * 24576000 ticks/sec).
81  *
82  * @param x time to wrap
83  * @return wrapped time
84  */
85 static inline uint32_t wrapAtMaxTicks(uint64_t x) {
86     if (x >= TICKS_PER_SECOND * 128L) {
87         x -= TICKS_PER_SECOND * 128L;
88     }
89
90 #ifdef DEBUG
91         if (x >= TICKS_PER_SECOND * 128L) {
92             debugWarning("insufficient wrapping: %llu\n",x);
93         }
94 #endif
95
96     return x;
97 }
98
99 /**
100  * @brief Wraps x to the minimum number of ticks
101  *
102  * The input value is wrapped to the minimum value of the cycle
103  * timer, in ticks (= 0).
104  *
105  * @param x time to wrap
106  * @return wrapped time
107  */
108 static inline uint32_t wrapAtMinTicks(int64_t x) {
109     if (x < 0) {
110         x += TICKS_PER_SECOND * 128L;
111     }
112
113 #ifdef DEBUG
114         if (x < 0) {
115             debugWarning("insufficient wrapping: %lld\n",x);
116            
117             debugWarning("correcting...\n");
118             while (x < 0) {
119                 x += TICKS_PER_SECOND * 128L;
120                
121                 if (x < 0) {
122                     debugWarning(" insufficient wrapping: %lld\n",x);
123                 }
124             }
125         }
126
127 #endif
128
129     return (uint32_t)x;
130 }
131
132 /**
133  * @brief Wraps both at minimum and maximum value for ticks
134  *
135  * The input value is wrapped to the maximum value of the cycle
136  * timer, in ticks (128sec * 24576000 ticks/sec), and
137  * to the minimum value of the cycle timer, in ticks (= 0).
138  *
139  * @param x value to wrap
140  * @return wrapped value
141  */
142 static inline uint32_t wrapAtMinMaxTicks(int64_t x) {
143    
144     if (x < 0) {
145         x += TICKS_PER_SECOND * 128L;
146     } else if (x >= TICKS_PER_SECOND * 128L) {
147         x -= TICKS_PER_SECOND * 128L;
148     }
149
150 #ifdef DEBUG
151         if (x >= TICKS_PER_SECOND * 128L) {
152             debugWarning("insufficient wrapping (max): %llu\n",x);
153         }
154         if (x < 0) {
155             debugWarning("insufficient wrapping (min): %lld\n",x);
156         }
157 #endif
158     return x;
159
160 }
161
162 /**
163  * @brief Computes a difference between timestamps
164  *
165  * This function computes a difference between timestamps
166  * such that it respects wrapping.
167  *
168  * If x wraps around, but y doesn't, the result of x-y is
169  * negative and very large. However the real difference is
170  * not large. It can be calculated by unwrapping x and then
171  * calculating x-y.
172  *
173  * @param x First timestamp
174  * @param y Second timestamp
175  * @return the difference x-y, unwrapped
176  */
177 static inline int32_t diffTicks(uint32_t x, uint32_t y) {
178     int64_t diff=(int64_t)x - (int64_t)y;
179    
180     // the maximal difference we allow (64secs)
181     const int64_t max=TICKS_PER_SECOND*64L;
182    
183     if(diff > max) {
184         // this means that y has wrapped, but
185         // x has not. we should unwrap y
186         // by adding TICKS_PER_SECOND*128L, meaning that we should substract
187         // this value from diff
188         diff -= TICKS_PER_SECOND*128L;
189     } else if (diff < -max) {
190         // this means that x has wrapped, but
191         // y has not. we should unwrap x
192         // by adding TICKS_PER_SECOND*128L, meaning that we should add
193         // this value to diff
194         diff += TICKS_PER_SECOND*128L;
195     }
196    
197     return (int32_t)diff;
198    
199 }
200
201 /**
202  * @brief Computes a sum of timestamps
203  *
204  * This function computes a sum of timestamps in ticks,
205  * wrapping the result if necessary.
206  *
207  * @param x First timestamp
208  * @param y Second timestamp
209  * @return the sum x+y, wrapped
210  */
211 static inline uint32_t addTicks(uint32_t x, uint32_t y) {
212     uint64_t sum=x+y;
213
214     return wrapAtMaxTicks(sum);
215 }
216
217 /**
218  * @brief Computes a substraction of timestamps
219  *
220  * This function computes a substraction of timestamps in ticks,
221  * wrapping the result if necessary.
222  *
223  * @param x First timestamp
224  * @param y Second timestamp
225  * @return the difference x-y, wrapped
226  */
227 static inline uint32_t substractTicks(uint32_t x, uint32_t y) {
228     int64_t subs=x-y;
229
230     return wrapAtMinTicks(subs);
231 }
232
233 /**
234  * @brief Converts a received SYT timestamp to a full timestamp in ticks.
235  *
236  *
237  * @param syt_timestamp The SYT timestamp as present in the packet
238  * @param rcv_cycle The cycle this timestamp was received on
239  * @param ctr_now The current value of the cycle timer ('now')
240  * @return
241  */
242 static inline uint32_t sytRecvToFullTicks(uint32_t syt_timestamp, unsigned int rcv_cycle, uint32_t ctr_now) {
243     uint32_t timestamp;
244    
245     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"SYT=%08X CY=%04X CTR=%08X\n",
246         syt_timestamp,rcv_cycle,ctr_now);
247        
248     // reconstruct the full cycle
249     uint32_t cc_cycles=CYCLE_TIMER_GET_CYCLES(ctr_now);
250     uint32_t cc_seconds=CYCLE_TIMER_GET_SECS(ctr_now);
251    
252     // the cycletimer has wrapped since this packet was received
253     // we want cc_seconds to reflect the 'seconds' at the point this
254     // was received
255     if (rcv_cycle>cc_cycles) {
256         if (cc_seconds) {
257             cc_seconds--;
258         } else {
259             // seconds has wrapped around, so we'd better not substract 1
260             // the good value is 127
261             cc_seconds=127;
262         }
263     }
264    
265     // reconstruct the top part of the timestamp using the current cycle number
266     uint32_t rcv_cycle_masked=rcv_cycle & 0xF;
267     uint32_t syt_cycle=CYCLE_TIMER_GET_CYCLES(syt_timestamp);
268    
269     // if this is true, wraparound has occurred, undo this wraparound
270     if(syt_cycle<rcv_cycle_masked) syt_cycle += 0x10;
271    
272     // this is the difference in cycles wrt the cycle the
273     // timestamp was received
274     uint32_t delta_cycles=syt_cycle-rcv_cycle_masked;
275    
276     // reconstruct the cycle part of the timestamp
277     uint32_t new_cycles=rcv_cycle + delta_cycles;
278    
279     // if the cycles cause a wraparound of the cycle timer,
280     // perform this wraparound
281     // and convert the timestamp into ticks
282     if(new_cycles<8000) {
283         timestamp  = new_cycles * TICKS_PER_CYCLE;
284     } else {
285         debugOutput(DEBUG_LEVEL_VERY_VERBOSE,
286             "Detected wraparound: %d + %d = %d\n",
287             rcv_cycle,delta_cycles,new_cycles);
288        
289         new_cycles-=8000; // wrap around
290 #ifdef DEBUG
291         if (new_cycles >= 8000) {
292             debugWarning("insufficient unwrapping\n");
293         }
294 #endif
295         timestamp  = new_cycles * TICKS_PER_CYCLE;
296         // add one second due to wraparound
297         timestamp += TICKS_PER_SECOND;
298     }
299    
300     timestamp += CYCLE_TIMER_GET_OFFSET(syt_timestamp);
301    
302     timestamp = addTicks(timestamp, cc_seconds * TICKS_PER_SECOND);
303    
304     #ifdef DEBUG
305         if(( TICKS_TO_CYCLE_TIMER(timestamp) & 0xFFFF) != syt_timestamp) {
306             debugWarning("back-converted timestamp not equal to SYT\n");
307             debugWarning("TS=%011llu TSC=%08X SYT=%04X\n",
308                   timestamp, TICKS_TO_CYCLE_TIMER(timestamp), syt_timestamp);
309         }
310     #endif
311    
312     return timestamp;
313 }
314
315 /**
316  * @brief Converts a transmit SYT timestamp to a full timestamp in ticks.
317  *
318  * The difference between sytRecvToFullTicks and sytXmitToFullTicks is
319  * the way SYT cycle wraparound is detected: in the receive version,
320  * wraparound is present if rcv_cycle > current_cycle. In the xmit
321  * version this is when current_cycle > xmt_cycle.
322  *
323  * @param syt_timestamp The SYT timestamp as present in the packet
324  * @param xmt_cycle The cycle this timestamp was received on
325  * @param ctr_now The current value of the cycle timer ('now')
326  * @return
327  */
328 static inline uint32_t sytXmitToFullTicks(uint32_t syt_timestamp, unsigned int xmt_cycle, uint32_t ctr_now) {
329     uint32_t timestamp;
330    
331     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"SYT=%08X CY=%04X CTR=%08X\n",
332         syt_timestamp,xmt_cycle,ctr_now);
333        
334     // reconstruct the full cycle
335     uint32_t cc_cycles=CYCLE_TIMER_GET_CYCLES(ctr_now);
336     uint32_t cc_seconds=CYCLE_TIMER_GET_SECS(ctr_now);
337    
338     // the cycletimer has wrapped since this packet was received
339     // we want cc_seconds to reflect the 'seconds' at the point this
340     // is to be transmitted
341     if (xmt_cycle<cc_cycles) {
342         if (cc_seconds) {
343             cc_seconds--;
344         } else {
345             // seconds has wrapped around, so we'd better not substract 1
346             // the good value is 127
347             cc_seconds=127;
348         }
349     }
350    
351     // reconstruct the top part of the timestamp using the current cycle number
352     uint32_t xmt_cycle_masked=xmt_cycle & 0xF;
353     uint32_t syt_cycle=CYCLE_TIMER_GET_CYCLES(syt_timestamp);
354    
355     // if this is true, wraparound has occurred, undo this wraparound
356     if(syt_cycle<xmt_cycle_masked) syt_cycle += 0x10;
357    
358     // this is the difference in cycles wrt the cycle the
359     // timestamp was received
360     uint32_t delta_cycles=syt_cycle-xmt_cycle_masked;
361    
362     // reconstruct the cycle part of the timestamp
363     uint32_t new_cycles=xmt_cycle + delta_cycles;
364    
365     // if the cycles cause a wraparound of the cycle timer,
366     // perform this wraparound
367     // and convert the timestamp into ticks
368     if(new_cycles<8000) {
369         timestamp  = new_cycles * TICKS_PER_CYCLE;
370     } else {
371         debugOutput(DEBUG_LEVEL_VERY_VERBOSE,
372             "Detected wraparound: %d + %d = %d\n",
373             xmt_cycle,delta_cycles,new_cycles);
374        
375         new_cycles-=8000; // wrap around
376 #ifdef DEBUG
377         if (new_cycles >= 8000) {
378             debugWarning("insufficient unwrapping\n");
379         }
380 #endif
381         timestamp  = new_cycles * TICKS_PER_CYCLE;
382         // add one second due to wraparound
383         timestamp += TICKS_PER_SECOND;
384     }
385    
386     timestamp += CYCLE_TIMER_GET_OFFSET(syt_timestamp);
387    
388     timestamp = addTicks(timestamp, cc_seconds * TICKS_PER_SECOND);
389    
390     #ifdef DEBUG
391         if(( TICKS_TO_CYCLE_TIMER(timestamp) & 0xFFFF) != syt_timestamp) {
392             debugWarning("back-converted timestamp not equal to SYT\n");
393             debugWarning("TS=%011llu TSC=%08X SYT=%04X\n",
394                   timestamp, TICKS_TO_CYCLE_TIMER(timestamp), syt_timestamp);
395         }
396     #endif
397    
398     return timestamp;
399 }
400
401 /**
402  * @brief Computes a difference between cycles
403  *
404  * This function computes a difference between cycles
405  * such that it respects wrapping (at 8000 cycles).
406  *
407  * See diffTicks
408  *
409  * @param x First cycle value
410  * @param y Second cycle value
411  * @return the difference x-y, unwrapped
412  */
413 static inline int diffCycles(unsigned int x, unsigned int y) {
414     int diff = x - y;
415    
416     // the maximal difference we allow (64secs)
417     const int max=CYCLES_PER_SECOND/2;
418    
419     if(diff > max) {
420         diff -= CYCLES_PER_SECOND;
421     } else if (diff < -max) {
422         diff += CYCLES_PER_SECOND;
423     }
424    
425     return diff;
426 }
427
428 #endif // __CYCLETIMER_H__
Note: See TracBrowser for help on using the browser.