Changeset 384
- Timestamp:
- 01/30/07 13:11:25 (17 years ago)
- Files:
-
- branches/streaming-rework/config.h.in (modified) (1 diff)
- branches/streaming-rework/configure.ac (modified) (3 diffs)
- branches/streaming-rework/src/bebob/bebob_avdevice.cpp (modified) (3 diffs)
- branches/streaming-rework/src/debugmodule/debugmodule.cpp (modified) (2 diffs)
- branches/streaming-rework/src/debugmodule/debugmodule.h (modified) (1 diff)
- branches/streaming-rework/src/devicemanager.cpp (modified) (2 diffs)
- branches/streaming-rework/src/libstreaming/AmdtpStreamProcessor.cpp (modified) (36 diffs)
- branches/streaming-rework/src/libstreaming/AmdtpStreamProcessor.h (modified) (6 diffs)
- branches/streaming-rework/src/libstreaming/cycletimer.h (modified) (2 diffs)
- branches/streaming-rework/src/libstreaming/freebob_streaming.cpp (modified) (5 diffs)
- branches/streaming-rework/src/libstreaming/IsoHandler.cpp (modified) (34 diffs)
- branches/streaming-rework/src/libstreaming/IsoHandler.h (modified) (8 diffs)
- branches/streaming-rework/src/libstreaming/IsoHandlerManager.cpp (modified) (14 diffs)
- branches/streaming-rework/src/libstreaming/IsoHandlerManager.h (modified) (3 diffs)
- branches/streaming-rework/src/libstreaming/IsoStream.cpp (modified) (2 diffs)
- branches/streaming-rework/src/libstreaming/MotuStreamProcessor.cpp (modified) (8 diffs)
- branches/streaming-rework/src/libstreaming/MotuStreamProcessor.h (modified) (5 diffs)
- branches/streaming-rework/src/libstreaming/StreamProcessor.cpp (modified) (6 diffs)
- branches/streaming-rework/src/libstreaming/StreamProcessor.h (modified) (6 diffs)
- branches/streaming-rework/src/libstreaming/StreamProcessorManager.cpp (modified) (21 diffs)
- branches/streaming-rework/src/libstreaming/StreamProcessorManager.h (modified) (5 diffs)
- branches/streaming-rework/src/libutil/cycles.h (modified) (1 diff)
- branches/streaming-rework/src/libutil/SystemTimeSource.cpp (modified) (2 diffs)
- branches/streaming-rework/src/libutil/SystemTimeSource.h (modified) (1 diff)
- branches/streaming-rework/src/libutil/Time.h (modified) (1 diff)
- branches/streaming-rework/src/libutil/TimeSource.cpp (modified) (2 diffs)
- branches/streaming-rework/src/libutil/TimeSource.h (modified) (2 diffs)
- branches/streaming-rework/src/Makefile.am (modified) (3 diffs)
- branches/streaming-rework/src/motu/motu_avdevice.cpp (modified) (2 diffs)
- branches/streaming-rework/src/motu/motu_avdevice.h (modified) (2 diffs)
- branches/streaming-rework/tests/Makefile.am (modified) (2 diffs)
- branches/streaming-rework/tests/SytMonitor.cpp (modified) (5 diffs)
- branches/streaming-rework/tests/SytMonitor.h (modified) (3 diffs)
- branches/streaming-rework/tests/test-cycletimer.cpp (modified) (9 diffs)
- branches/streaming-rework/tests/test-sytmonitor.cpp (modified) (15 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/streaming-rework/config.h.in
r365 r384 84 84 #undef const 85 85 86 /* Define to `unsigned int' if <sys/types.h> does not define. */86 /* Define to `unsigned' if <sys/types.h> does not define. */ 87 87 #undef size_t 88 88 branches/streaming-rework/configure.ac
r358 r384 113 113 114 114 # Check for dependencies 115 PKG_CHECK_MODULES(LIBRAW1394_122, libraw1394 >= 1.2.2, libraw1394_1_2_2=yes, libraw1394_1_2_2=no) 115 116 PKG_CHECK_MODULES(LIBRAW1394, libraw1394 >= 1.2.1) 116 117 PKG_CHECK_MODULES(LIBIEC61883, libiec61883 >= 1.0.0) … … 129 130 esac],[debug=false]) 130 131 132 if test "x$libraw1394_1_2_2" = xyes; then 133 CFLAGS="$CFLAGS -DLIBRAW1394_USE_CTRREAD_API" 134 CXXFLAGS="$CXXFLAGS -DLIBRAW1394_USE_CTRREAD_API" 135 fi 131 136 132 137 dnl Check for MMX assembly … … 248 253 Source directory: $srcdir 249 254 Installation prefix: $prefix 255 C compiler: $C $CFLAGS 250 256 C++ compiler: $CXX $CXXFLAGS 251 257 252 258 libraw1394 CFLAGS: $LIBRAW1394_CFLAGS 253 259 libraw1394 LIBS: $LIBRAW1394_LIBS 260 use new cycle timer read api? $libraw1394_1_2_2 254 261 libiec61883 CFLAGS: $LIBIEC61883_CFLAGS 255 262 libiec61883 LIBS: $LIBIEC61883_LIBS branches/streaming-rework/src/bebob/bebob_avdevice.cpp
r379 r384 993 993 } 994 994 995 // FIXME: do this the proper way!996 m_transmitProcessor->syncmaster=m_receiveProcessor;997 998 995 if (!addPlugToProcessor(*inputPlug,m_transmitProcessor, 999 996 FreebobStreaming::AmdtpAudioPort::E_Playback)) { … … 1110 1107 } 1111 1108 1109 // FIXME: error checking 1112 1110 int 1113 1111 AvDevice::startStreamByIndex(int i) { … … 1171 1169 break; 1172 1170 default: 1173 return 0;1171 return -1; 1174 1172 } 1175 1173 // } 1176 1174 1175 if (iso_channel < 0) return -1; 1176 1177 1177 return 0; 1178 1178 1179 1179 } 1180 1180 1181 // FIXME: error checking 1181 1182 int 1182 1183 AvDevice::stopStreamByIndex(int i) { branches/streaming-rework/src/debugmodule/debugmodule.cpp
r383 r384 213 213 DebugModuleManager::registerModule( DebugModule& debugModule ) 214 214 { 215 bool already_present=false; 216 217 for ( DebugModuleVectorIterator it = m_debugModules.begin(); 218 it != m_debugModules.end(); 219 ++it ) 220 { 221 if ( *it == &debugModule ) { 222 already_present=true; 223 return true; 224 } 225 } 226 227 if (already_present) { 228 cerr << "DebugModuleManager::registerModule: Module already registered: " 229 << "DebugModule (" << debugModule.getName() << ")" << endl; 230 } else { 215 231 m_debugModules.push_back( &debugModule ); 232 } 216 233 return true; 217 234 } … … 220 237 DebugModuleManager::unregisterModule( DebugModule& debugModule ) 221 238 { 239 222 240 for ( DebugModuleVectorIterator it = m_debugModules.begin(); 223 241 it != m_debugModules.end(); branches/streaming-rework/src/debugmodule/debugmodule.h
r341 r384 136 136 #define CHECK_PREEMPTION(onoff) 137 137 #endif 138 139 // Intel recommends that a serializing instruction140 // should be called before and after rdtsc.141 // CPUID is a serializing instruction.142 #define read_rdtsc(time) \143 __asm__ __volatile__( \144 "pushl %%ebx\n\t" \145 "cpuid\n\t" \146 "rdtsc\n\t" \147 "mov %%eax,(%0)\n\t" \148 "cpuid\n\t" \149 "popl %%ebx\n\t" \150 : /* no output */ \151 : "S"(&time) \152 : "eax", "ecx", "edx", "memory")153 154 static inline unsigned long debugGetCurrentTSC() {155 unsigned retval;156 read_rdtsc(retval);157 return retval;158 }159 138 160 139 unsigned char toAscii( unsigned char c ); branches/streaming-rework/src/devicemanager.cpp
r368 r384 153 153 } 154 154 155 #ifdef ENABLE_MOTU 155 156 if ( MAudio::AvDevice::probe( *configRom.get() ) ) { 156 157 return new MAudio::AvDevice( configRom, *m_1394Service, id, level ); 157 158 } 158 159 160 159 161 if ( Motu::MotuDevice::probe( *configRom.get() ) ) { 160 162 return new Motu::MotuDevice( configRom, *m_1394Service, id, level ); … … 168 170 return new Bounce::BounceDevice( configRom, *m_1394Service, id, level ); 169 171 } 172 #endif 170 173 171 174 return 0; branches/streaming-rework/src/libstreaming/AmdtpStreamProcessor.cpp
r383 r384 31 31 #include "AmdtpPort.h" 32 32 33 #include "cycle counter.h"33 #include "cycletimer.h" 34 34 35 35 #include <netinet/in.h> 36 36 #include <assert.h> 37 37 38 #define RECEIVE_PROCESSING_DELAY_IN_SAMPLES 10039 38 #define RECEIVE_DLL_INTEGRATION_COEFFICIENT 0.015 40 39 41 #define RECEIVE_PROCESSING_DELAY (TICKS_PER_SECOND * 2/1000)40 #define RECEIVE_PROCESSING_DELAY 51200 42 41 43 42 // in ticks 44 #define TRANSMIT_TRANSFER_DELAY 10000 43 #define TRANSMIT_TRANSFER_DELAY 1000 44 #define TRANSMIT_ADVANCE_CYCLES 10 45 45 46 46 //#define DO_SYT_SYNC … … 80 80 } 81 81 82 83 82 return true; 84 83 } … … 97 96 unsigned int nevents=0; 98 97 99 packet->eoh0 = 0;98 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Xmit handler for cycle %d\n",cycle); 100 99 101 100 #ifdef DEBUG … … 121 120 m_running=true; 122 121 123 // don't process the stream when it is not enabled. 124 // however, we do have to generate (semi) valid packets 125 // that means that we'll send NODATA packets FIXME: check!! 126 if(m_disabled) { 122 // we calculate the timestamp of the next sample in the buffer, which will 123 // allow us to check if we are to send this sample now, or later 124 125 // FIXME: maybe we should use the buffer head timestamp for this? 126 127 float ticks_per_frame=m_SyncSource->getTicksPerFrame(); 128 129 // the base timestamp is the one of the last sample in the buffer 130 int64_t timestamp = m_buffer_tail_timestamp; 131 132 133 // meaning that the first sample in the buffer lies m_framecounter * rate 134 // earlier. This would give the next equation: 135 // timestamp = m_last_timestamp - m_framecounter * rate 136 // but to preserve causality, we have to make sure that this timestamp is 137 // always bigger than m_last_timestamp. this can be done by adding 138 // m_ringbuffersize_frames * rate. 139 timestamp += (int64_t)((((int64_t)m_ringbuffer_size_frames) 140 - ((int64_t)m_framecounter)) 141 * ticks_per_frame); 142 143 // this happens if m_buffer_tail_timestamp wraps around while there are 144 // not much frames in the buffer. We should add the wraparound value of the ticks 145 // counter 146 if (timestamp < 0) { 147 timestamp += TICKS_PER_SECOND * 128L; 148 } 149 // this happens when the last timestamp is near wrapping, and 150 // m_framecounter is low. 151 // this means: m_last_timestamp is near wrapping and have just had 152 // a getPackets() from the client side. the projected next_period 153 // boundary lies beyond the wrap value. 154 // the action is to wrap the value. 155 else if (timestamp >= TICKS_PER_SECOND * 128L) { 156 timestamp -= TICKS_PER_SECOND * 128L; 157 } 158 159 // determine if we want to send a packet or not 160 uint64_t cycle_timer=m_handler->getCycleTimerTicks(); 161 162 int64_t until_next=timestamp-cycle_timer; 163 164 // we send a packet some cycles in advance, to avoid the 165 // following situation: 166 // suppose we are only a few ticks away from 167 // the moment to send this packet. This means that in 168 // order to keep causality, we have to make sure that 169 // the TRANSFER_DELAY is bigger than one cycle, which 170 // might be a little much. 171 // this means that we need one cycle of extra buffering. 172 until_next -= TICKS_PER_CYCLE * TRANSMIT_ADVANCE_CYCLES; 173 174 // the maximal difference we can allow (64secs) 175 const int64_t max=TICKS_PER_SECOND*64L; 176 177 if(!m_disabled) { 178 debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "=> TS=%11llu, CTR=%11llu, FC=%5d, TPS=%10.6f, UTN=%11lld\n", 179 timestamp, cycle_timer, m_framecounter, ticks_per_frame, until_next 180 ); 181 } 182 183 if(until_next > max) { 184 // this means that cycle_timer has wrapped, but 185 // timestamp has not. we should unwrap cycle_timer 186 // by adding TICKS_PER_SECOND*128L, meaning that we should substract 187 // this value from until_next 188 until_next -= TICKS_PER_SECOND*128L; 189 } else if (until_next < -max) { 190 // this means that timestamp has wrapped, but 191 // cycle_timer has not. we should unwrap timestamp 192 // by adding TICKS_PER_SECOND*128L, meaning that we should add 193 // this value from until_next 194 until_next += TICKS_PER_SECOND*128L; 195 } 196 197 if(!m_disabled) { 198 debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " TS=%11llu, CTR=%11llu, FC=%5d, TPS=%10.6f, UTN=%11lld\n", 199 timestamp, cycle_timer, m_framecounter, ticks_per_frame, until_next 200 ); 201 } 202 203 // don't process the stream when it is not enabled, 204 // or when the next sample is not due yet. 205 206 // we do have to generate (semi) valid packets 207 // that means that we'll send NODATA packets. 208 // we don't add payload because DICE devices don't like that. 209 if((until_next>0) || m_disabled) { 127 210 // no-data packets have syt=0xFFFF 128 // and have the usual amount of events as dummy data 211 // and have the usual amount of events as dummy data (?) 129 212 packet->fdf = IEC61883_FDF_NODATA; 130 213 packet->syt = 0xffff; … … 133 216 m_dbc += m_syt_interval; 134 217 218 // this means no-data packets with payload (DICE doesn't like that) 135 219 *length = 2*sizeof(quadlet_t) + m_syt_interval * m_dimension * sizeof(quadlet_t); 220 221 // this means no-data packets without payload 222 //*length = 2*sizeof(quadlet_t); 223 136 224 *tag = IEC61883_TAG_WITH_CIP; 137 225 *sy = 0; … … 140 228 } 141 229 142 packet->fdf = m_fdf; 143 144 // assert(m_handler->getDroppedCount()<5); 145 146 // debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "get packet...\n"); 147 148 // construct the packet cip 149 // NOTE: maybe a little outdated 150 // FIXME: this should be done differently: 151 // first we should determine the timestamp of the first sample in this block 152 // this can be done by reading the rate of the compagnion receiver 153 // this rate will give us the ticks per sample used by the device 154 // then we should take the previous timestamp, and add m_syt_interval * ticks_per_sample 155 // to this timestamp (only if we are sending events). This gives us the timestamp 156 // of the first sample in this packet. 157 // we should define a transfer delay and add it to this timestamp and then send it to 158 // the device. 159 160 // NOTE: this will even work when we're only transmitting (no receive stream): 161 // the ticks_per_sample value is initialized by the receive streamprocessor 162 // to the nominal value. We will then transmit at our own pace, being at nominal 163 // rate compared to the cycle counter. 164 165 // NOTE: this scheme might even work when sync'ing on the sync streams of the device 166 // they are AMDTP streams with SYT timestamps, therefore a decent estimate of 167 // ticks_per_frame can be found, and we are synced when using it. 168 169 // <<compile error here>> 170 171 // FIXME: if m_last_bufferfill > 0 172 float ticks_per_frame=syncmaster->getTicksPerFrame(); 173 174 // m_last_timestamp is the moment upon which the last 'period signal' 175 // should have been given (note: should have been because 176 // the timestamp is derrived from the incoming packets, 177 // not from the moment the signal was actually given) 178 179 // at a period boundary, we expect m_ringbuffer_size_frames frames to 180 // be in the buffers. 'right after' the transfer(), all of these 181 // frames should be in the xmit buffers (if transfer() finishes 182 // before new packets are received) 183 // therefore the last sample of the xmit buffer lies at 184 // T1 = timestamp + (m_ringbuffer_size_frames) * ticks_per_frame 185 186 // in reality however life is multithreaded, and we don't know 187 // exactly how many samples there are in the buffer. but we know 188 // how many there should be, so we say that the last frame put 189 // into the buffer (by transfer) has the timestamp T1 190 191 // this means that the current sample has timestamp 192 // T2 = T1 - ticks_per_frame * (nb_frames_in_buffer) 193 // = T1 - ticks_per_frame * (m_ringbuffer_size_frames-m_framecounter) 194 // = timestamp + ticks_per_frame * 195 // (m_ringbuffer_size_frames-m_ringbuffer_size_frames+m_framecounter) 196 // = timestamp + ticks_per_frame * m_framecounter 197 198 int T2 = m_last_timestamp + ticks_per_frame*m_framecounter; 199 200 // we then need to add the transfer delay for the receiving 201 // device to this time to determine the xmit timestamp 202 // TSTAMP = T2 + TRANSFER_DELAY 203 204 // we should determine when to 'queue' this sample to 205 // the ISO xmit layer, based upon the cycle parameter 206 // we can define the ideal time at which to send the sample as 207 // TSEND = TSTAMP - TRANSFER_DELAY 208 // being T2 209 int TSEND = T2; 210 211 // the xmit timestamp should then be the TSEND + TRANSMIT_TRANSFER_DELAY 212 // note that in this setup, TRANSMIT_TRANSFER_DELAY has to incorporate the 213 // iso buffering 214 int timestamp = TSEND + TRANSMIT_TRANSFER_DELAY; 215 216 // if we take a look at TSEND we can determine if we are to send 217 // the sample or not: 218 // if 219 // CYCLES(TSEND) < cycle 220 // then the time at which to send the packet has passed (note: wraparound!) 221 // we should send the sample 222 // if it hasn't passed, we should send an empty packet 223 // 224 // this should automatically catch up 225 226 // FIXME: wraparound! 227 int cycle_wo_wraparound=cycle; 228 229 int TSEND_cycle_wo_wraparound = TICKS_TO_CYCLES(TSEND); 230 231 // arbitrary, should be replaced by a better wraparound 232 // detection 233 234 // if cycles wraps around, and TSEND_cyles doesn't, 235 // we need to make sure that we compare the right things 236 // i.e. unwrap the cycle parameter 237 // if both wrap, this can't be true 238 if (cycle_wo_wraparound - TSEND_cycle_wo_wraparound < -4000) { 239 cycle_wo_wraparound += 8000; 240 241 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"wraparound on cycle detected: %d %d %d\n", 242 cycle, cycle_wo_wraparound, 243 cycle - TSEND_cycle_wo_wraparound); 244 } 245 246 // if TSEND_cycle wraps around and cycle doesn't, 247 // TSEND_cycle suddenly becomes a lot smaller than cycle 248 if (TSEND_cycle_wo_wraparound - cycle_wo_wraparound < -4000) { 249 TSEND_cycle_wo_wraparound += 8000; 250 251 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"wraparound on TSEND detected: %d %d %d\n", 252 TICKS_TO_CYCLES(TSEND), TSEND_cycle_wo_wraparound, 253 TSEND_cycle_wo_wraparound - cycle_wo_wraparound); 254 } 255 256 if (TSEND_cycle_wo_wraparound < cycle_wo_wraparound) { 257 nevents=m_syt_interval; 258 m_dbc += m_syt_interval; 259 260 } else { // no-data 261 262 // no-data packets have syt=0xFFFF 263 // and have the usual amount of events as dummy data 230 // construct the packet 231 nevents = m_syt_interval; 232 m_dbc += m_syt_interval; 233 234 *tag = IEC61883_TAG_WITH_CIP; 235 *sy = 0; 236 237 enum raw1394_iso_disposition retval; 238 239 unsigned int read_size=nevents*sizeof(quadlet_t)*m_dimension; 240 241 if ((freebob_ringbuffer_read(m_event_buffer,(char *)(data+8),read_size)) < 242 read_size) 243 { 244 /* there is no more data in the ringbuffer */ 245 246 debugWarning("Transmit buffer underrun (cycle %d, FC=%d, PC=%d)\n", 247 cycle, m_framecounter, m_handler->getPacketCount()); 248 249 // TODO: we have to be a little smarter here 250 // because we have some slack on the device side (TRANSFER_DELAY) 251 // we can allow some skipped packets 252 // signal underrun 253 m_xruns++; 254 255 // compose a no-data packet, we should always 256 // send a valid packet 264 257 packet->fdf = IEC61883_FDF_NODATA; 265 258 packet->syt = 0xffff; 266 259 267 // the dbc is incremented even with no data packets 268 m_dbc += m_syt_interval; 269 270 *length = 2*sizeof(quadlet_t) + m_syt_interval * m_dimension * sizeof(quadlet_t); 271 *tag = IEC61883_TAG_WITH_CIP; 272 *sy = 0; 273 274 // if(packet->dbs) { 275 // debugOutput(DEBUG_LEVEL_VERY_VERBOSE, 276 // "XMT %04d: CH = %d, FDF = %X. SYT = %6d, DBS = %3d, DBC = %3d, FMT = %3d, LEN = %4d (%2d)\n", 277 // cycle, m_channel, packet->fdf, 278 // packet->syt, 279 // packet->dbs, 280 // packet->dbc, 281 // packet->fmt, 282 // *length, 283 // ((*length / sizeof (quadlet_t)) - 2)/packet->dbs); 284 // } 285 286 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Sending empty packet on cycle %d\n", cycle); 287 288 // FIXME: this is to prevent libraw to do loop over too 289 // much packets at once (overflowing the receive side) 290 // but putting it here is a little arbitrary 291 292 293 return RAW1394_ISO_DEFER; 294 } 295 296 297 // debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Now=%4d/%8d, Tstamp=%8d, DT=%8d, T2=%8d, T3=%8d, last TS=%d, BF=%d\n", 298 // cycle,(cycle*3072), 299 // timestamp, 300 // timestamp-(cycle*3072), 301 // T2,T3, 302 // m_last_timestamp, 303 // buffer_fill); 304 305 enum raw1394_iso_disposition retval = RAW1394_ISO_OK; 306 307 unsigned int read_size=nevents*sizeof(quadlet_t)*m_dimension; 308 309 if ((freebob_ringbuffer_read(m_event_buffer,(char *)(data+8),read_size)) < 310 read_size) 311 { 312 /* there is no more data in the ringbuffer */ 313 314 debugWarning("Transmit buffer underrun (cycle %d, FC=%d, PC=%d)\n", 315 cycle, m_framecounter, m_handler->getPacketCount()); 316 317 // signal underrun 318 m_xruns++; 260 // this means no-data packets with payload (DICE doesn't like that) 261 *length = 2*sizeof(quadlet_t) + m_syt_interval * m_dimension * sizeof(quadlet_t); 262 263 // this means no-data packets without payload 264 //*length = 2*sizeof(quadlet_t); 319 265 320 266 retval=RAW1394_ISO_DEFER; 321 *length=0;322 nevents=0;323 324 325 267 } else { 326 retval=RAW1394_ISO_OK;327 268 *length = read_size + 8; 328 269 329 270 // process all ports that should be handled on a per-packet base 330 271 // this is MIDI for AMDTP (due to the need of DBC) … … 332 273 debugWarning("Problem encoding Packet Ports\n"); 333 274 } 334 335 // we can forget the seconds for the cycle counter 336 // because we are masking with 0xFFFF 337 338 unsigned int timestamp_SYT = (TICKS_TO_CYCLES(timestamp) << 12) 339 | TICKS_TO_OFFSET(timestamp); 340 341 packet->syt = ntohs(timestamp_SYT & 0xffff); 342 343 // debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"XMIT %d EVENTS, SYT %04X for cycle %2d: %08d (%2u cycles + %04u ticks)\n", 344 // nevents, timestamp_SYT & 0xFFFF, cycle, timestamp_SYT 345 // CYCLE_COUNTER_GET_CYCLES(timestamp_SYT), 346 // CYCLE_COUNTER_GET_OFFSET(timestamp_SYT) 347 // ); 348 } 349 350 *tag = IEC61883_TAG_WITH_CIP; 351 *sy = 0; 352 353 // update the frame counter 354 incrementFrameCounter(nevents); 355 356 /* if(m_framecounter>m_period) { 357 retval=RAW1394_ISO_DEFER; 358 }*/ 359 360 #ifdef DEBUG 361 // if(packet->dbs) { 362 // debugOutput(DEBUG_LEVEL_VERY_VERBOSE, 363 // "XMT %04d: CH = %d, FDF = %X. SYT = %6d, DBS = %3d, DBC = %3d, FMT = %3d, LEN = %4d (%2d)\n", 364 // cycle, m_channel, packet->fdf, 365 // packet->syt, 366 // packet->dbs, 367 // packet->dbc, 368 // packet->fmt, 369 // *length, 370 // ((*length / sizeof (quadlet_t)) - 2)/packet->dbs); 371 // } 372 #endif 275 276 packet->fdf = m_fdf; 277 278 // convert the timestamp to SYT format 279 unsigned int timestamp_SYT = TICKS_TO_SYT(timestamp); 280 packet->syt = ntohs(timestamp_SYT); 281 282 retval=RAW1394_ISO_OK; 283 } 284 285 // calculate the new buffer head timestamp. this is 286 // the timestamp of the current packet plus 287 // SYT_INTERVAL * rate 288 289 timestamp += (int64_t)((float)m_syt_interval * ticks_per_frame ); 290 291 // check if it wrapped 292 if (timestamp >= TICKS_PER_SECOND * 128L) { 293 timestamp -= TICKS_PER_SECOND * 128L; 294 } 295 296 // update the frame counter such that it reflects the new value 297 // also update the buffer head timestamp 298 // done in the SP base class 299 if (!StreamProcessor::getFrames(nevents, timestamp)) { 300 debugError("Could not do StreamProcessor::getFrames(%d, %llu)\n",nevents, timestamp); 301 retval=RAW1394_ISO_ERROR; 302 } 373 303 374 304 return retval; … … 376 306 } 377 307 378 void AmdtpTransmitStreamProcessor::decrementFrameCounter() { 379 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "decrement frame counter...\n"); 380 381 #ifdef DEBUG 382 int xmit_bufferspace=freebob_ringbuffer_read_space(m_event_buffer)/m_dimension/4; 383 int recv_bufferspace=freebob_ringbuffer_read_space(syncmaster->m_event_buffer)/syncmaster->m_dimension/4; 384 385 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"XMT: %5d | RCV: %5d | DIFF: %5d | SUM: %5d \n", xmit_bufferspace, recv_bufferspace, xmit_bufferspace - recv_bufferspace, xmit_bufferspace + recv_bufferspace); 386 #endif 387 388 // update the timestamp 389 390 m_last_timestamp=syncmaster->getPeriodTimeStamp(); 391 392 StreamProcessor::decrementFrameCounter(); 393 } 394 395 void AmdtpTransmitStreamProcessor::incrementFrameCounter(int nbframes) { 396 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "increment frame counter by %d...\n", nbframes); 397 398 StreamProcessor::incrementFrameCounter(nbframes); 399 } 400 401 bool AmdtpTransmitStreamProcessor::isOnePeriodReady() 402 { 403 return true; 404 //return (m_framecounter > m_period); 308 int64_t AmdtpTransmitStreamProcessor::getTimeUntilNextPeriodUsecs() { 309 debugFatal("IMPLEMENT ME!"); 310 return 0; 311 } 312 313 uint64_t AmdtpTransmitStreamProcessor::getTimeAtPeriodUsecs() { 314 // then we should convert this into usecs 315 // FIXME: we assume that the TimeSource of the IsoHandler is 316 // in usecs. 317 return m_handler->mapToTimeSource(getTimeAtPeriod()); 318 } 319 320 uint64_t AmdtpTransmitStreamProcessor::getTimeAtPeriod() { 321 debugFatal("IMPLEMENT ME!"); 322 323 return 0; 405 324 } 406 325 407 326 bool AmdtpTransmitStreamProcessor::prefill() { 408 409 327 if(!transferSilence(m_ringbuffer_size_frames)) { 410 328 debugFatal("Could not prefill transmit stream\n"); … … 412 330 } 413 331 414 /* int i=m_nb_buffers; 415 while(i--) { 416 if(!transferSilence(m_period)) { 417 debugFatal("Could not prefill transmit stream\n"); 418 return false; 419 } 420 } 421 422 // and we should also provide enough prefill for the 423 // SYT processing delay 424 if(!transferSilence(RECEIVE_PROCESSING_DELAY_IN_SAMPLES)) { 425 debugFatal("Could not prefill transmit stream (2)\n"); 332 // when the buffer is prefilled, we should 333 // also initialize the base timestamp 334 // this base timestamp is the timestamp of the 335 // last buffer transfer. 336 uint64_t ts; 337 uint64_t fc; 338 m_SyncSource->getBufferHeadTimestamp(&ts, &fc); 339 340 // update the frame counter such that it reflects the buffer content, 341 // and also update the buffer tail timestamp 342 // done in the SP base class 343 if (!StreamProcessor::putFrames(m_ringbuffer_size_frames, ts)) { 344 debugError("Could not do StreamProcessor::putFrames(%d, %llu)\n", 345 m_ringbuffer_size_frames, ts); 426 346 return false; 427 347 } 428 */ 429 // the framecounter should be pulled back to 430 // make sure the ISO buffering is used 431 // we are using 1 period of iso buffering 432 // m_framecounter=-m_period; 433 434 // should this also be pre-buffered? 435 //m_framecounter=-(m_framerate * RECEIVE_PROCESSING_DELAY)/TICKS_PER_SECOND; 436 348 437 349 return true; 438 350 … … 524 436 m_ringbuffer_size_frames=m_nb_buffers * m_period; 525 437 526 // add the processing delay 527 m_ringbuffer_size_frames+=RECEIVE_PROCESSING_DELAY_IN_SAMPLES; 438 // prepare the framerate estimate 439 m_ticks_per_frame = (TICKS_PER_SECOND*1.0) / ((float)m_framerate); 440 441 // add the receive processing delay 442 m_ringbuffer_size_frames+=(uint)(RECEIVE_PROCESSING_DELAY/m_ticks_per_frame); 528 443 529 444 if( !(m_event_buffer=freebob_ringbuffer_create( 530 445 (m_dimension * m_ringbuffer_size_frames) * sizeof(quadlet_t)))) { 531 446 debugFatal("Could not allocate memory event ringbuffer"); 532 // return -ENOMEM;533 447 return false; 534 448 } … … 539 453 freebob_ringbuffer_free(m_event_buffer); 540 454 return false; 541 // return -ENOMEM;542 455 } 543 456 … … 633 546 return false; 634 547 } 635 636 // we should prefill the event buffer 548 549 // prefilling is done in ...() 550 // because at that point the streams are running, 551 // while here they are not. 552 553 // prefill the event buffer 637 554 if (!prefill()) { 638 555 debugFatal("Could not prefill buffers\n"); … … 652 569 } 653 570 571 bool AmdtpTransmitStreamProcessor::prepareForStart() { 572 573 return true; 574 } 575 576 bool AmdtpTransmitStreamProcessor::prepareForStop() { 577 disable(); 578 return true; 579 } 580 581 bool AmdtpTransmitStreamProcessor::prepareForEnable() { 582 uint64_t ts; 583 uint64_t fc; 584 585 m_SyncSource->getBufferHeadTimestamp(&ts, &fc); 586 587 setBufferTailTimestamp(ts); 588 589 return true; 590 } 591 654 592 bool AmdtpTransmitStreamProcessor::transferSilence(unsigned int size) { 655 593 /* a naive implementation would look like this: */ … … 668 606 } 669 607 670 bool AmdtpTransmitStreamProcessor::transfer() { 608 bool AmdtpTransmitStreamProcessor::canClientTransferFrames(unsigned int nbframes) { 609 // there has to be enough space to put the frames in 610 return m_ringbuffer_size_frames - getFrameCounter() > nbframes; 611 } 612 613 bool AmdtpTransmitStreamProcessor::putFrames(unsigned int nbframes, int64_t ts) { 671 614 m_PeriodStat.mark(freebob_ringbuffer_read_space(m_event_buffer)/(4*m_dimension)); 672 615 673 616 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Transferring period...\n"); 674 // TODO: improve675 /* a naive implementation would look like this:676 677 unsigned int write_size=m_period*sizeof(quadlet_t)*m_dimension;678 char *dummybuffer=(char *)calloc(sizeof(quadlet_t),m_period*m_dimension);679 transmitBlock(dummybuffer, m_period, 0, 0);680 681 if (freebob_ringbuffer_write(m_event_buffer,(char *)(dummybuffer),write_size) < write_size) {682 debugWarning("Could not write to event buffer\n");683 }684 685 686 free(dummybuffer);687 */688 /* but we're not that naive anymore... */689 617 int xrun; 690 618 unsigned int offset=0; … … 693 621 // we received one period of frames 694 622 // this is period_size*dimension of events 695 int events2write= m_period*m_dimension;623 int events2write=nbframes*m_dimension; 696 624 int bytes2write=events2write*sizeof(quadlet_t); 697 625 … … 709 637 int byteswritten=0; 710 638 711 unsigned int frameswritten=( m_period*cluster_size-bytes2write)/cluster_size;639 unsigned int frameswritten=(nbframes*cluster_size-bytes2write)/cluster_size; 712 640 offset=frameswritten; 713 641 … … 761 689 // xrun detected 762 690 debugError("XMT: Frame buffer underrun in processor %p\n",this); 763 break; 691 break; // FIXME: return false ? 764 692 } 765 693 … … 771 699 assert(bytes2write%cluster_size==0); 772 700 701 } 702 703 // update the frame counter such that it reflects the new value, 704 // and also update the buffer tail timestamp 705 // done in the SP base class 706 debugOutput(DEBUG_LEVEL_VERBOSE, "StreamProcessor::putFrames(%d, %llu)\n",nbframes, ts); 707 708 if (!StreamProcessor::putFrames(nbframes, ts)) { 709 debugError("Could not do StreamProcessor::putFrames(%d, %llu)\n",nbframes, ts); 710 return false; 773 711 } 774 712 … … 859 797 860 798 quadlet_t *target_event=NULL; 861 int j;799 unsigned int j; 862 800 863 801 for ( PortVectorIterator it = m_PacketPorts.begin(); … … 989 927 990 928 AmdtpReceiveStreamProcessor::AmdtpReceiveStreamProcessor(int port, int framerate, int dimension) 991 : ReceiveStreamProcessor(port, framerate), m_dimension(dimension), m_last_timestamp(0), m_last_timestamp2(0) , m_one_period_passed(false){929 : ReceiveStreamProcessor(port, framerate), m_dimension(dimension), m_last_timestamp(0), m_last_timestamp2(0) { 992 930 993 931 … … 1021 959 struct iec61883_packet *packet = (struct iec61883_packet *) data; 1022 960 assert(packet); 1023 unsigned long in_time=debugGetCurrentTSC();1024 961 1025 962 #ifdef DEBUG … … 1029 966 #endif 1030 967 1031 // how are we going to get this right???1032 // m_running=true;1033 1034 968 if((packet->fmt == 0x10) && (packet->fdf != 0xFF) && (packet->syt != 0xFFFF) && (packet->dbs>0) && (length>=2*sizeof(quadlet_t))) { 1035 969 unsigned int nevents=((length / sizeof (quadlet_t)) - 2)/packet->dbs; 1036 970 1037 // signal that we're running 1038 if(nevents) m_running=true; 1039 1040 1041 // do the time stamp processing 1042 // put the last time stamp a variable 1043 // this will allow us to determine the 1044 // actual presentation time later 1045 bool wraparound_occurred=false; 1046 971 //=> store the previous timestamp 1047 972 m_last_timestamp2=m_last_timestamp; 1048 973 974 //=> convert the SYT to ticks 1049 975 unsigned int syt_timestamp=ntohs(packet->syt); 976 977 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"ch%2u: CY=%4u, SYT=%08X (%3u secs + %4u cycles + %04u ticks)\n", 978 channel, cycle,syt_timestamp, CYCLE_TIMER_GET_SECS(syt_timestamp), 979 CYCLE_TIMER_GET_CYCLES(syt_timestamp), CYCLE_TIMER_GET_OFFSET(syt_timestamp)); 980 981 // reconstruct the full cycle 982 unsigned int cc=m_handler->getCycleTimer(); 983 unsigned int cc_cycles=CYCLE_TIMER_GET_CYCLES(cc); 984 unsigned int cc_seconds=CYCLE_TIMER_GET_SECS(cc); 985 986 // the cycletimer has wrapped since this packet was received 987 // we want cc_seconds to reflect the 'seconds' at the point this 988 // was received 989 if (cycle>cc_cycles) { 990 if (cc_seconds) { 991 cc_seconds--; 992 } else { 993 // seconds has wrapped around, so we'd better not substract 1 994 // the good value is 127 995 cc_seconds=127; 996 } 997 } 998 1050 999 // reconstruct the top part of the timestamp using the current cycle number 1051 1000 unsigned int now_cycle_masked=cycle & 0xF; 1052 unsigned int syt_cycle=CYCLE_ COUNTER_GET_CYCLES(syt_timestamp);1001 unsigned int syt_cycle=CYCLE_TIMER_GET_CYCLES(syt_timestamp); 1053 1002 1054 1003 // if this is true, wraparound has occurred, undo this wraparound 1055 1004 if(syt_cycle<now_cycle_masked) syt_cycle += 0x10; 1056 1005 1006 // this is the difference in cycles wrt the cycle the 1007 // timestamp was received 1057 1008 unsigned int delta_cycles=syt_cycle-now_cycle_masked; 1058 1009 … … 1060 1011 unsigned int new_cycles=cycle + delta_cycles; 1061 1012 1062 if(new_cycles>7999) { 1063 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Detected wraparound: %d + %d = %d\n",cycle,delta_cycles,new_cycles); 1013 // if the cycles cause a wraparound of the cycle timer, 1014 // perform this wraparound 1015 // and convert the timestamp into ticks 1016 if(new_cycles<8000) { 1017 m_last_timestamp = new_cycles * TICKS_PER_CYCLE; 1018 } else { 1019 debugOutput(DEBUG_LEVEL_VERY_VERBOSE, 1020 "Detected wraparound: %d + %d = %d\n", 1021 cycle,delta_cycles,new_cycles); 1064 1022 1065 1023 new_cycles-=8000; // wrap around 1066 wraparound_occurred=true; 1024 m_last_timestamp = new_cycles * TICKS_PER_CYCLE; 1025 // add one second due to wraparound 1026 m_last_timestamp += TICKS_PER_SECOND; 1067 1027 } 1068 1028 1069 m_last_timestamp = (new_cycles) << 12; 1070 1071 // now add the offset part on top of that 1072 m_last_timestamp |= (syt_timestamp & 0xFFF); 1073 1074 // mask off the seconds field 1075 1076 // m_last_timestamp timestamp now contains all info, 1077 // including cycle number 1078 1079 if (m_last_timestamp && m_last_timestamp2) { 1080 // try and estimate the frame rate from the device: 1081 int measured_difference=((int)(CYCLE_COUNTER_TO_TICKS(m_last_timestamp))) 1082 -((int)(CYCLE_COUNTER_TO_TICKS(m_last_timestamp2))); 1029 m_last_timestamp += CYCLE_TIMER_GET_OFFSET(syt_timestamp); 1030 m_last_timestamp += cc_seconds * TICKS_PER_SECOND; 1031 1032 //=> now estimate the device frame rate 1033 if (m_last_timestamp2 && m_last_timestamp) { 1034 // try and estimate the frame rate from the device 1083 1035 1084 // handle wrap around of the cycle variable if nescessary 1085 // it can be that two successive timestamps cause wraparound 1086 // (if the difference between time stamps is larger than 2 cycles), 1087 // thus it isn't always nescessary 1088 if (wraparound_occurred & (m_last_timestamp<m_last_timestamp2)) { 1089 debugOutput(DEBUG_LEVEL_VERY_VERBOSE," => correcting for timestamp difference wraparound\n"); 1090 measured_difference+=TICKS_PER_SECOND; 1036 // first get the measured difference between both 1037 // timestamps 1038 int64_t measured_difference; 1039 measured_difference=((int64_t)(m_last_timestamp)) 1040 -((int64_t)(m_last_timestamp2)); 1041 // correct for seconds wraparound 1042 if (m_last_timestamp<m_last_timestamp2) { 1043 measured_difference+=128L*TICKS_PER_SECOND; 1091 1044 } 1092 1045 … … 1096 1049 float err = f / (1.0*m_syt_interval) - m_ticks_per_frame; 1097 1050 1098 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"SYT: %08X | STMP: % 08X | DLL: in=%5.0f, current=%f, err=%e\n",syt_timestamp, m_last_timestamp, f,m_ticks_per_frame,err);1051 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"SYT: %08X | STMP: %lluticks | DLL: in=%f, current=%f, err=%e\n",syt_timestamp, m_last_timestamp, f,m_ticks_per_frame,err); 1099 1052 1100 1053 #ifdef DEBUG 1054 // this helps to detect wraparound issues 1101 1055 if(f > 1.5*((TICKS_PER_SECOND*1.0) / m_framerate)*m_syt_interval) { 1102 1056 debugWarning("Timestamp diff more than 50%% of the nominal diff too large!\n"); 1103 debugWarning(" SYT: %08X | STMP: %08X,%08X | DLL: in=%5.0f, current=%f, err=%e\n",syt_timestamp, m_last_timestamp, m_last_timestamp2, f,m_ticks_per_frame,err); 1057 debugWarning(" SYT: %08X | STMP: %llu,%llu | DLL: in=%f, current=%f, err=%e\n",syt_timestamp, m_last_timestamp, m_last_timestamp2, f,m_ticks_per_frame,err); 1058 debugWarning(" CC: %08X | CC_CY: %u | CC_SEC: %u | SYT_CY: %u | NEW_CY: %u\n", 1059 cc, cc_cycles, cc_seconds, syt_cycle,new_cycles); 1060 1104 1061 } 1105 1062 if(f < 0.5*((TICKS_PER_SECOND*1.0) / m_framerate)*m_syt_interval) { 1106 1063 debugWarning("Timestamp diff more than 50%% of the nominal diff too small!\n"); 1107 debugWarning(" SYT: %08X | STMP: % 08X,%08X | DLL: in=%5.0f, current=%f, err=%e\n",syt_timestamp, m_last_timestamp, m_last_timestamp2, f,m_ticks_per_frame,err);1064 debugWarning(" SYT: %08X | STMP: %llu,%llu | DLL: in=%f, current=%f, err=%e\n",syt_timestamp, m_last_timestamp, m_last_timestamp2, f,m_ticks_per_frame,err); 1108 1065 } 1109 1066 #endif 1110 1111 1067 // integrate the error 1112 1068 m_ticks_per_frame += RECEIVE_DLL_INTEGRATION_COEFFICIENT*err; … … 1116 1072 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"R-SYT for cycle (%2d %2d)=>%2d: %5uT (%04uC + %04uT) %04X %04X %d\n", 1117 1073 cycle,now_cycle_masked,delta_cycles, 1118 CYCLE_COUNTER_TO_TICKS(m_last_timestamp),1119 CYCLE_COUNTER_GET_CYCLES(m_last_timestamp),1120 CYCLE_COUNTER_GET_OFFSET(m_last_timestamp),1121 ntohs(packet->syt),m_last_timestamp&0xFFFF, dropped1074 (m_last_timestamp), 1075 TICKS_TO_CYCLES(m_last_timestamp), 1076 TICKS_TO_OFFSET(m_last_timestamp), 1077 ntohs(packet->syt),TICKS_TO_CYCLE_TIMER(m_last_timestamp)&0xFFFF, dropped 1122 1078 ); 1123 1079 1124 #ifdef DEBUG 1125 if(m_last_timestamp<m_last_timestamp2) { 1126 if(wraparound_occurred) { 1127 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"timestamp not sequential for cycle %d, but it's wraparound. %08X %08X %08X\n",cycle,syt_timestamp, m_last_timestamp, m_last_timestamp2); 1128 } else { 1129 debugWarning("timestamp not sequential for cycle %d! %08X %08X %08X\n", cycle, syt_timestamp, m_last_timestamp, m_last_timestamp2); 1130 1131 // the DLL will recover from this. 1132 // ??? m_last_timestamp2=m_last_timestamp-(m_syt_interval*m_ticks_per_frame); 1133 } 1134 } 1135 #endif 1136 1137 // don't process the stream samples when it is not enabled. 1080 //=> signal that we're running (if we are) 1081 if(!m_running && nevents && m_last_timestamp2 && m_last_timestamp) m_running=true; 1082 1083 //=> don't process the stream samples when it is not enabled. 1138 1084 if(m_disabled) { 1085 // we keep track of the timestamp here 1086 // this makes sure that we will have a somewhat accurate 1087 // estimate as to when a period might be ready. i.e. it will not 1088 // be ready earlier than this timestamp + period time 1089 1090 // the next (possible) sample is not this one, but lies 1091 // SYT_INTERVAL * rate later 1092 uint64_t ts=m_last_timestamp+(uint64_t)((float)m_syt_interval * m_ticks_per_frame); 1093 StreamProcessor::setBufferTimestamps(ts,ts); 1094 1139 1095 return RAW1394_ISO_DEFER; 1140 1096 } 1141 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "put packet...\n");1142 1097 1098 //=> process the packet 1143 1099 unsigned int write_size=nevents*sizeof(quadlet_t)*m_dimension; 1100 1144 1101 // add the data payload to the ringbuffer 1145 1146 1102 if (freebob_ringbuffer_write(m_event_buffer,(char *)(data+8),write_size) < write_size) 1147 1103 { 1148 1104 debugWarning("Receive buffer overrun (cycle %d, FC=%d, PC=%d)\n", 1149 1105 cycle, m_framecounter, m_handler->getPacketCount()); 1106 1150 1107 m_xruns++; 1151 1108 … … 1159 1116 retval=RAW1394_ISO_DEFER; 1160 1117 } 1161 1162 1118 } 1163 1119 … … 1176 1132 #endif 1177 1133 1178 // update the frame counter 1179 incrementFrameCounter(nevents); 1180 if(m_framecounter>(signed int)m_period) { 1181 retval=RAW1394_ISO_DEFER; 1182 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"defer!\n"); 1134 // update the frame counter such that it reflects the new value, 1135 // and also update the buffer tail timestamp, as we add new frames 1136 // done in the SP base class 1137 if (!StreamProcessor::putFrames(nevents, m_last_timestamp)) { 1138 debugError("Could not do StreamProcessor::putFrames(%d, %llu)\n",nevents, m_last_timestamp); 1139 return RAW1394_ISO_ERROR; 1183 1140 } 1184 1141 1185 } else { 1186 // discard packet 1187 // can be important for sync though 1188 1189 // FIXME: this is to prevent libraw to do loop over too 1190 // much packets at once (draining the xmit side) 1191 // but putting it here is a little arbitrary 1192 retval=RAW1394_ISO_DEFER; 1193 } 1194 1195 m_PacketStat.mark(debugGetCurrentTSC()-in_time); 1196 1197 // m_PacketStat.mark(freebob_ringbuffer_read_space(m_event_buffer)/(4*m_dimension)); 1142 } 1198 1143 1199 1144 return retval; 1200 1145 } 1201 1146 1202 // this uses SYT to determine if one period is ready 1203 bool AmdtpReceiveStreamProcessor::isOnePeriodReady() { 1204 1205 #ifdef DO_SYT_SYNC 1206 // this code is not ready yet 1207 1208 // one sample will take a number off cycle counter ticks: 1209 // The number of ticks per second is 24576000 1210 // The number of samples per second is Fs 1211 // therefore the number of ticks per sample is 24576000 / Fs 1212 // NOTE: this will be rounded!! 1213 // float ticks_per_sample=24576000.0/m_framerate; 1214 float ticks_per_sample=m_ticks_per_frame; 1215 1216 // we are allowed to add some constant 1217 // processing delay to the transfer delay 1218 // being the period size and some fixed delay 1219 // unsigned int processing_delay=ticks_per_sample*(m_period)+RECEIVE_PROCESSING_DELAY; 1220 unsigned int processing_delay=ticks_per_sample*(m_period+RECEIVE_PROCESSING_DELAY_IN_SAMPLES); 1221 1222 // the number of events in the buffer is 1223 // m_framecounter 1224 1225 // we have the timestamp of the last event block: 1226 // m_last_timestamp 1227 1228 // the time at which the beginning of the buffer should be 1229 // presented to the audio side is: 1230 // m_last_timestamp - (m_framecounter-m_syt_interval)*ticks_per_sample 1231 1232 // NOTE: in fact, we don't have to check this, because it should always be the case 1233 // 1234 // WAS: however we have to make sure that we can transfer at least one period 1235 // therefore we first check if this is ok 1236 1237 // if(m_framecounter > (signed int)m_period) { 1238 1239 unsigned int m_last_timestamp_ticks = CYCLE_COUNTER_TO_TICKS(m_last_timestamp); 1240 1241 // add the processing delay 1242 int ideal_presentation_time = m_last_timestamp_ticks + processing_delay; 1243 int buffer_content_ticks=((int)m_framecounter)-((int)m_syt_interval); 1244 buffer_content_ticks *= ticks_per_sample; 1245 1246 // if the ideal_presentation_time is smaller than buffer_content_ticks, wraparound has occurred 1247 // for the cycle part of m_last_timestamp. Therefore add one second worth of ticks 1248 // to the cycle counter, as this is the wraparound point. 1249 if (ideal_presentation_time < buffer_content_ticks) ideal_presentation_time += 24576000; 1250 // we can now safely substract these, it will always be > 0 1251 ideal_presentation_time -= buffer_content_ticks; 1252 1253 // FIXME: if we are sure, make ideal_presentation_time an unsigned int 1254 // assert(ideal_presentation_time>=0); 1255 1256 unsigned int current_time_ticks = (m_handler->getCycleCounter() % TICKS_PER_SECOND ); 1257 1258 #ifdef DEBUG 1259 if(ideal_presentation_time<0) { 1260 debugWarning("ideal_presentation_time time is negative!\n"); 1261 debugOutput(DEBUG_LEVEL_VERBOSE,"Periods: %d, FC: %d, remote framerate %f\n", 1262 m_PeriodStat.m_count, m_framecounter, m_ticks_per_frame); 1263 debugOutput(DEBUG_LEVEL_VERBOSE,"p-delay: %u, buffer_content: %d\n", 1264 processing_delay, buffer_content_ticks); 1265 debugOutput(DEBUG_LEVEL_VERBOSE,"Timestamp : %10u ticks (%3u secs + %4u cycles + %04u ticks)\n", 1266 m_last_timestamp_ticks, 1267 CYCLE_COUNTER_GET_SECS(m_last_timestamp), 1268 CYCLE_COUNTER_GET_CYCLES(m_last_timestamp), 1269 CYCLE_COUNTER_GET_OFFSET(m_last_timestamp) 1270 ); 1271 debugOutput(DEBUG_LEVEL_VERBOSE,"P-TIME : %10d ticks (%3u secs + %4u cycles + %04u ticks)\n", 1272 ideal_presentation_time, 1273 TICKS_TO_SECS(ideal_presentation_time), 1274 TICKS_TO_CYCLES(ideal_presentation_time), 1275 TICKS_TO_OFFSET(ideal_presentation_time) 1276 ); 1277 debugOutput(DEBUG_LEVEL_VERBOSE,"Now : %10u ticks (%3u secs + %4u cycles + %04u ticks)\n", 1278 current_time_ticks, 1279 TICKS_TO_SECS(current_time_ticks), 1280 TICKS_TO_CYCLES(current_time_ticks), 1281 TICKS_TO_OFFSET(current_time_ticks) 1282 ); 1283 return false; 1284 } 1285 if(ideal_presentation_time<m_last_timestamp_ticks) { 1286 debugWarning("ideal_presentation_time earlier than last timestamp!\n"); 1287 debugOutput(DEBUG_LEVEL_VERBOSE,"Periods: %d, FC: %d, remote framerate %f\n", 1288 m_PeriodStat.m_count, m_framecounter, m_ticks_per_frame); 1289 debugOutput(DEBUG_LEVEL_VERBOSE,"p-delay: %u, buffer_content: %u\n", 1290 processing_delay, buffer_content_ticks); 1291 debugOutput(DEBUG_LEVEL_VERBOSE,"Timestamp : %10u ticks (%3u secs + %4u cycles + %04u ticks)\n", 1292 m_last_timestamp_ticks, 1293 CYCLE_COUNTER_GET_SECS(m_last_timestamp), 1294 CYCLE_COUNTER_GET_CYCLES(m_last_timestamp), 1295 CYCLE_COUNTER_GET_OFFSET(m_last_timestamp) 1296 ); 1297 debugOutput(DEBUG_LEVEL_VERBOSE,"P-TIME : %10d ticks (%3u secs + %4u cycles + %04u ticks)\n", 1298 ideal_presentation_time, 1299 TICKS_TO_SECS(ideal_presentation_time), 1300 TICKS_TO_CYCLES(ideal_presentation_time), 1301 TICKS_TO_OFFSET(ideal_presentation_time) 1302 ); 1303 debugOutput(DEBUG_LEVEL_VERBOSE,"Now : %10u ticks (%3u secs + %4u cycles + %04u ticks)\n", 1304 current_time_ticks, 1305 TICKS_TO_SECS(current_time_ticks), 1306 TICKS_TO_CYCLES(current_time_ticks), 1307 TICKS_TO_OFFSET(current_time_ticks) 1308 ); 1309 1310 } 1311 #endif 1312 1313 // if the last signalled period lies in the future, we know we had wraparound of the clock 1314 // so add one second 1315 // if (current_time_ticks < m_previous_signal_ticks) current_time_ticks += 24576000; 1316 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Periods: %d, remote framerate %f\n",m_PeriodStat.m_count, m_ticks_per_frame); 1317 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Timestamp : %10u ticks (%3u secs + %4u cycles + %04u ticks)\n", 1318 m_last_timestamp_ticks, 1319 CYCLE_COUNTER_GET_SECS(m_last_timestamp), 1320 CYCLE_COUNTER_GET_CYCLES(m_last_timestamp), 1321 CYCLE_COUNTER_GET_OFFSET(m_last_timestamp) 1322 ); 1323 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"P-TIME : %10d ticks (%3u secs + %4u cycles + %04u ticks)\n", 1324 ideal_presentation_time, 1325 ideal_presentation_time/24576000, 1326 (ideal_presentation_time/3072) % 8000, 1327 ideal_presentation_time%3072 1328 ); 1329 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Now : %10u ticks (%3u secs + %4u cycles + %04u ticks)\n", 1330 current_time_ticks, 1331 TICKS_TO_SECS(current_time_ticks), 1332 TICKS_TO_CYCLES(current_time_ticks), 1333 TICKS_TO_OFFSET(current_time_ticks) 1334 ); 1335 1336 int tmp=ideal_presentation_time-current_time_ticks; 1337 1338 // if current_time_ticks wraps around while ahead of the presentation time, we have 1339 // a problem. 1340 // we know however that we have to wait for at max one buffer + some transmit delay 1341 // therefore we clip this value at 0.5 seconds 1342 if (tmp > 24576000/2) tmp-=24576000; 1343 1344 if(tmp<0) { 1345 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"SYT passed (%d ticks too late)\n",-tmp); 1346 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Periods: %d, remote ticks/frame: %f, remote framerate = %f\n", 1347 m_PeriodStat.m_count, m_ticks_per_frame, 24576000.0/m_ticks_per_frame); 1348 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Bufferfill %d, framecounter %d\n", 1349 freebob_ringbuffer_read_space(m_event_buffer)/(4*m_dimension),m_framecounter); 1350 if (-tmp>1000000) debugWarning("SYT VERY LATE: %d!\n",-tmp); 1351 1352 m_WakeupStat.mark(m_framecounter); 1353 1354 m_one_period_passed=true; 1355 m_last_timestamp_at_period_ticks=ideal_presentation_time; 1356 1357 return true; 1358 } else { 1359 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Too early wait %d ticks\n",tmp); 1360 return false; 1361 } 1362 // } else { 1363 // return false; 1364 // } 1365 #else 1366 if(m_framecounter > m_period) { 1367 return true; 1368 } else return false; 1369 #endif 1370 } 1371 1372 unsigned int AmdtpReceiveStreamProcessor::getPeriodTimeStamp() { 1373 if (m_one_period_passed) { 1374 return m_last_timestamp_at_period_ticks; 1375 } else { 1376 // float ticks_per_sample=24576000.0/m_framerate; 1377 float ticks_per_sample=m_ticks_per_frame; 1378 1379 // we are allowed to add some constant 1380 // processing delay to the transfer delay 1381 // being the period size and some fixed delay 1382 // unsigned int processing_delay=ticks_per_sample*(m_period)+RECEIVE_PROCESSING_DELAY; 1383 unsigned int processing_delay=ticks_per_sample*(m_period+RECEIVE_PROCESSING_DELAY_IN_SAMPLES); 1384 1385 unsigned int m_last_timestamp_ticks = CYCLE_COUNTER_TO_TICKS(m_last_timestamp); 1386 1387 // add the processing delay 1388 int ideal_presentation_time = m_last_timestamp_ticks + processing_delay; 1389 unsigned int buffer_content_ticks=(int)((m_framecounter-m_syt_interval)*ticks_per_sample); 1390 1391 // if the ideal_presentation_time is smaller than buffer_content_ticks, wraparound has occurred 1392 // for the cycle part of m_last_timestamp. Therefore add one second worth of ticks 1393 // to the cycle counter, as this is the wraparound point. 1394 if (ideal_presentation_time < buffer_content_ticks) ideal_presentation_time += 24576000; 1395 // we can now safely substract these, it will always be > 0 1396 ideal_presentation_time -= buffer_content_ticks; 1397 1398 return ideal_presentation_time; 1399 } 1147 int64_t AmdtpReceiveStreamProcessor::getTimeUntilNextPeriodUsecs() { 1148 uint64_t time_at_period=getTimeAtPeriod(); 1149 1150 uint64_t cycle_timer=m_handler->getCycleTimerTicks(); 1151 1152 int64_t until_next=time_at_period-cycle_timer; 1153 1154 // the maximal difference we can allow (64secs) 1155 const int64_t max=TICKS_PER_SECOND*64L; 1156 1157 debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "=> TAP=%11llu, CTR=%11llu, UTN=%11lld, TPUS=%f\n", 1158 time_at_period, cycle_timer, until_next, m_handler->getTicksPerUsec() 1159 ); 1160 1161 if(until_next > max) { 1162 // this means that cycle_timer has wrapped, but 1163 // time_at_period has not. we should unwrap cycle_timer 1164 // by adding TICKS_PER_SECOND*128L, meaning that we should substract 1165 // this value from until_next 1166 until_next -= TICKS_PER_SECOND*128L; 1167 } else if (until_next < -max) { 1168 // this means that time_at_period has wrapped, but 1169 // cycle_timer has not. we should unwrap time_at_period 1170 // by adding TICKS_PER_SECOND*128L, meaning that we should add 1171 // this value from until_next 1172 until_next += TICKS_PER_SECOND*128L; 1173 } 1174 1175 debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " TAP=%11llu, CTR=%11llu, UTN=%11lld, TPUS=%f\n", 1176 time_at_period, cycle_timer, until_next, m_handler->getTicksPerUsec() 1177 ); 1178 1179 // now convert to usecs 1180 // don't use the mapping function because it only works 1181 // for absolute times, not the relative time we are 1182 // using here (which can also be negative). 1183 return (int64_t)(((float)until_next) / m_handler->getTicksPerUsec()); 1184 } 1185 1186 uint64_t AmdtpReceiveStreamProcessor::getTimeAtPeriodUsecs() { 1187 // then we should convert this into usecs 1188 // FIXME: we assume that the TimeSource of the IsoHandler is 1189 // in usecs. 1190 return m_handler->mapToTimeSource(getTimeAtPeriod()); 1191 } 1192 1193 uint64_t AmdtpReceiveStreamProcessor::getTimeAtPeriod() { 1194 1195 // every time a packet is received both the framecounter and the base 1196 // timestamp are updated. This means that at any instance of time, the 1197 // front of the buffer (latest sample) timestamp is known. 1198 // As we know the number of frames in the buffer, and we now the rate 1199 // in ticks/frame, we can calculate the back of buffer timestamp as: 1200 // back_of_buffer_time = front_time - nbframes * rate 1201 // the next period boundary time lies m_period frames later: 1202 // next_period_boundary = back_of_buffer_time + m_period * rate 1203 1204 // NOTE: we should account for the fact that the timestamp is not for 1205 // the latest sample, but for the latest sample minus syt_interval-1 1206 // because it is the timestamp for the first sample in the packet, 1207 // while the complete packet contains SYT_INTERVAL samples. 1208 // this makes the equation: 1209 // back_of_buffer_time = front_time - (nbframes - (syt_interval - 1)) * rate 1210 // next_period_boundary = back_of_buffer_time + m_period * rate 1211 1212 // NOTE: where do we add the processing delay? 1213 // if we add it here: 1214 // next_period_boundary += RECEIVE_PROCESSING_DELAY 1215 1216 // the complete equation now is: 1217 // next_period_boundary = front_time - (nbframes - (syt_interval - 1)) * rate 1218 // + m_period * rate + RECEIVE_PROCESSING_DELAY 1219 // since syt_interval is a constant value, we can equally well ignore it, as 1220 // if it were already included in RECEIVE_PROCESSING_DELAY 1221 // making the equation (simplified: 1222 // next_period_boundary = front_time + (-nbframes + m_period) * rate 1223 // + RECEIVE_PROCESSING_DELAY 1224 // currently this is in ticks 1225 1226 int64_t next_period_boundary = m_last_timestamp; 1227 next_period_boundary += (int64_t)(((int64_t)m_period-(int64_t)m_framecounter) * m_ticks_per_frame); 1228 next_period_boundary += RECEIVE_PROCESSING_DELAY; 1229 1230 debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "=> NPD=%11lld, LTS=%11llu, FC=%5d, TPF=%f\n", 1231 next_period_boundary, m_last_timestamp, m_framecounter, m_ticks_per_frame 1232 ); 1233 1234 // this happens if the timestamp wraps around while there are a lot of 1235 // frames in the buffer. We should add the wraparound value of the ticks 1236 // counter 1237 if (next_period_boundary < 0) { 1238 next_period_boundary += TICKS_PER_SECOND * 128L; 1239 } 1240 // this happens when the last timestamp is near wrapping, and 1241 // m_framecounter is low. 1242 // this means: m_last_timestamp is near wrapping and have just had 1243 // a getPackets() from the client side. the projected next_period 1244 // boundary lies beyond the wrap value. 1245 // the action is to wrap the value. 1246 else if (next_period_boundary >= TICKS_PER_SECOND * 128L) { 1247 next_period_boundary -= TICKS_PER_SECOND * 128L; 1248 } 1249 1250 debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " NPD=%11lld, LTS=%11llu, FC=%5d, TPF=%f\n", 1251 next_period_boundary, m_last_timestamp, m_framecounter, m_ticks_per_frame 1252 ); 1253 1254 return next_period_boundary; 1400 1255 } 1401 1256 … … 1424 1279 freebob_ringbuffer_reset(m_event_buffer); 1425 1280 1426 // reset the last timestamp1427 m_last_timestamp=0;1428 1429 1281 m_PeriodStat.reset(); 1430 1282 m_PacketStat.reset(); 1431 1283 m_WakeupStat.reset(); 1432 1433 // reset the framerate estimate 1434 m_ticks_per_frame = (TICKS_PER_SECOND*1.0) / m_framerate; 1435 1436 debugOutput(DEBUG_LEVEL_VERBOSE,"Initializing remote ticks/frame to %f\n",m_ticks_per_frame); 1437 1438 //reset the timestamps 1439 m_last_timestamp=0; 1440 m_last_timestamp2=0; 1441 1442 m_one_period_passed=false; 1284 1285 m_ticks_per_frame = (TICKS_PER_SECOND*1.0) / ((float)m_framerate); 1443 1286 1444 1287 // reset all non-device specific stuff … … 1491 1334 1492 1335 // prepare the framerate estimate 1493 m_ticks_per_frame = (TICKS_PER_SECOND*1.0) / m_framerate;1336 m_ticks_per_frame = (TICKS_PER_SECOND*1.0) / ((float)m_framerate); 1494 1337 1495 1338 debugOutput(DEBUG_LEVEL_VERBOSE,"Initializing remote ticks/frame to %f\n",m_ticks_per_frame); … … 1500 1343 // add the processing delay 1501 1344 debugOutput(DEBUG_LEVEL_VERBOSE,"Adding %u frames of SYT slack buffering...\n", 1502 RECEIVE_PROCESSING_DELAY_IN_SAMPLES);1503 ringbuffer_size_frames+= RECEIVE_PROCESSING_DELAY_IN_SAMPLES;1345 (uint)(RECEIVE_PROCESSING_DELAY/m_ticks_per_frame)); 1346 ringbuffer_size_frames+=(uint)(RECEIVE_PROCESSING_DELAY/m_ticks_per_frame); 1504 1347 1505 1348 if( !(m_event_buffer=freebob_ringbuffer_create( … … 1601 1444 } 1602 1445 1603 bool AmdtpReceiveStreamProcessor::transfer() { 1446 bool AmdtpReceiveStreamProcessor::prepareForStart() { 1447 disable(); 1448 return true; 1449 } 1450 1451 bool AmdtpReceiveStreamProcessor::prepareForStop() { 1452 disable(); 1453 return true; 1454 } 1455 1456 bool AmdtpReceiveStreamProcessor::canClientTransferFrames(unsigned int nbframes) { 1457 return getFrameCounter() >= (int) nbframes; 1458 } 1459 1460 bool AmdtpReceiveStreamProcessor::getFrames(unsigned int nbframes, int64_t ts) { 1604 1461 1605 1462 m_PeriodStat.mark(freebob_ringbuffer_read_space(m_event_buffer)/(4*m_dimension)); … … 1607 1464 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Transferring period...\n"); 1608 1465 1609 /* another naive section:1610 unsigned int read_size=m_period*sizeof(quadlet_t)*m_dimension;1611 char *dummybuffer=(char *)calloc(sizeof(quadlet_t),m_period*m_dimension);1612 if (freebob_ringbuffer_read(m_event_buffer,(char *)(dummybuffer),read_size) < read_size) {1613 debugWarning("Could not read from event buffer\n");1614 }1615 1616 receiveBlock(dummybuffer, m_period, 0);1617 1618 free(dummybuffer);1619 */1620 1466 int xrun; 1621 1467 unsigned int offset=0; … … 1625 1471 // this is period_size*dimension of events 1626 1472 1627 int events2read= m_period*m_dimension;1473 int events2read=nbframes*m_dimension; 1628 1474 int bytes2read=events2read*sizeof(quadlet_t); 1629 1475 /* read events2read bytes from the ringbuffer … … 1638 1484 1639 1485 while(bytes2read>0) { 1640 unsigned int framesread=( m_period*cluster_size-bytes2read)/cluster_size;1486 unsigned int framesread=(nbframes*cluster_size-bytes2read)/cluster_size; 1641 1487 offset=framesread; 1642 1488 … … 1695 1541 assert(bytes2read%cluster_size==0); 1696 1542 } 1697 1698 return true; 1543 1544 // update the frame counter such that it reflects the new value, 1545 // and also update the buffer head timestamp as we pull frames 1546 // done in the SP base class 1547 1548 // wrap the timestamp if nescessary 1549 if (ts < 0) { 1550 ts += TICKS_PER_SECOND * 128L; 1551 } else if (ts >= TICKS_PER_SECOND * 128L) { 1552 ts -= TICKS_PER_SECOND * 128L; 1553 } 1554 1555 if (!StreamProcessor::getFrames(nbframes, ts)) { 1556 debugError("Could not do StreamProcessor::getFrames(%d, %llu)\n",nbframes, ts); 1557 return false; 1558 } 1559 1560 return true; 1699 1561 } 1700 1562 … … 1752 1614 1753 1615 quadlet_t *target_event=NULL; 1754 int j;1616 unsigned int j; 1755 1617 1756 1618 for ( PortVectorIterator it = m_PacketPorts.begin(); branches/streaming-rework/src/libstreaming/AmdtpStreamProcessor.h
r383 r384 38 38 #include <libiec61883/iec61883.h> 39 39 #include "ringbuffer.h" 40 #include <pthread.h> 40 41 41 42 #define AMDTP_MAX_PACKET_SIZE 2048 … … 88 89 bool reset(); 89 90 bool prepare(); 90 bool transfer(); 91 virtual void setVerboseLevel(int l); 92 93 bool isOnePeriodReady(); 91 92 bool prepareForStop(); 93 bool prepareForStart(); 94 95 bool prepareForEnable(); 96 97 bool canClientTransferFrames(unsigned int nbframes); 98 bool putFrames(unsigned int nbframes, int64_t ts); ///< transfer the buffer contents from the client 94 99 95 100 // We have 1 period of samples = m_period … … 103 108 104 109 unsigned int getMaxPacketSize() {return 4 * (2 + m_syt_interval * m_dimension);}; 105 106 // FIXME: do this the proper way! 107 AmdtpReceiveStreamProcessor *syncmaster; 108 109 // this updates the timestamp, and the 110 // 'bufferfill' 111 // should be called from the same thread 112 // that does the iteration 113 void decrementFrameCounter(); 114 void incrementFrameCounter(int nbframes); 110 111 int64_t getTimeUntilNextPeriodUsecs(); 112 113 uint64_t getTimeAtPeriodUsecs(); 114 uint64_t getTimeAtPeriod(); 115 116 void setVerboseLevel(int l); 115 117 116 118 protected: … … 177 179 bool reset(); 178 180 bool prepare(); 179 bool transfer(); 180 181 virtual void setVerboseLevel(int l); 182 183 bool isOnePeriodReady(); 184 181 182 bool prepareForStop(); 183 bool prepareForStart(); 184 185 bool canClientTransferFrames(unsigned int nbframes); 186 bool getFrames(unsigned int nbframes, int64_t ts); ///< transfer the buffer contents to the client 187 185 188 // We have 1 period of samples = m_period 186 189 // this period takes m_period/m_framerate seconds of time … … 194 197 unsigned int getMaxPacketSize() {return 4 * (2 + m_syt_interval * m_dimension);}; 195 198 196 float getTicksPerFrame() {return m_ticks_per_frame;};197 unsigned int getPeriodTimeStamp();198 199 199 void dumpInfo(); 200 200 201 int64_t getTimeUntilNextPeriodUsecs(); 202 203 uint64_t getTimeAtPeriodUsecs(); 204 uint64_t getTimeAtPeriod(); 205 206 void setVerboseLevel(int l); 207 201 208 protected: 202 209 … … 211 218 unsigned int m_syt_interval; 212 219 213 unsigned int m_last_timestamp; 214 unsigned int m_last_timestamp2; 215 unsigned int m_last_timestamp_at_period_ticks; 216 217 float m_ticks_per_frame; 218 219 bool m_one_period_passed; 220 uint64_t m_last_timestamp; /// last timestamp (in ticks) 221 uint64_t m_last_timestamp2; /// last timestamp (in ticks) 222 uint64_t m_last_timestamp_at_period_ticks; 220 223 221 224 DECLARE_DEBUG_MODULE; branches/streaming-rework/src/libstreaming/cycletimer.h
r383 r384 27 27 */ 28 28 29 /* Definitions and utility macro's to handle the ISO cycle counter */29 /* Definitions and utility macro's to handle the ISO cycle timer */ 30 30 31 #ifndef __CYCLE COUNTER_H__32 #define __CYCLE COUNTER_H__31 #ifndef __CYCLETIMER_H__ 32 #define __CYCLETIMER_H__ 33 33 34 34 #define CSR_CYCLE_TIME 0x200 35 35 #define CSR_REGISTER_BASE 0xfffff0000000ULL 36 36 37 #define CYCLES_PER_SECOND 8000 38 #define TICKS_PER_CYCLE 3072 39 #define TICKS_PER_SECOND (CYCLES_PER_SECOND * TICKS_PER_CYCLE)37 #define CYCLES_PER_SECOND 8000U 38 #define TICKS_PER_CYCLE 3072U 39 #define TICKS_PER_SECOND 24576000UL 40 40 #define TICKS_PER_USEC (TICKS_PER_SECOND/1000000.0) 41 41 42 42 #define USECS_PER_TICK (1.0/TICKS_PER_USEC) 43 43 44 #define CYCLE_ COUNTER_GET_SECS(x) ((((x) & 0xFE000000) >> 25))45 #define CYCLE_ COUNTER_GET_CYCLES(x) ((((x) & 0x01FFF000) >> 12))46 #define CYCLE_ COUNTER_GET_OFFSET(x) ((((x) & 0x00000FFF)))47 #define CYCLE_ COUNTER_TO_TICKS(x) ((CYCLE_COUNTER_GET_SECS(x) * TICKS_PER_SECOND) +\48 (CYCLE_ COUNTER_GET_CYCLES(x) * TICKS_PER_CYCLE ) +\49 (CYCLE_ COUNTER_GET_OFFSET(x) ))44 #define CYCLE_TIMER_GET_SECS(x) ((((x) & 0xFE000000U) >> 25)) 45 #define CYCLE_TIMER_GET_CYCLES(x) ((((x) & 0x01FFF000U) >> 12)) 46 #define CYCLE_TIMER_GET_OFFSET(x) ((((x) & 0x00000FFFU))) 47 #define CYCLE_TIMER_TO_TICKS(x) ((CYCLE_TIMER_GET_SECS(x) * TICKS_PER_SECOND) +\ 48 (CYCLE_TIMER_GET_CYCLES(x) * TICKS_PER_CYCLE ) +\ 49 (CYCLE_TIMER_GET_OFFSET(x) )) 50 50 51 51 // non-efficient versions, to be avoided in critical code … … 54 54 #define TICKS_TO_OFFSET(x) (((x)%TICKS_PER_CYCLE)) 55 55 56 #define CYCLE_COUNTER_UNWRAP_TICKS(x) ((x) \ 57 + (127 * TICKS_PER_SECOND) \ 56 #define TICKS_TO_CYCLE_TIMER(x) ( ((TICKS_TO_SECS(x) & 0x7F) << 25) \ 57 | ((TICKS_TO_CYCLES(x) & 0x1FFF) << 12) \ 58 | ((TICKS_TO_OFFSET(x) & 0xFFF))) 59 60 #define TICKS_TO_SYT(x) (((TICKS_TO_CYCLES(x) & 0xF) << 12) \ 61 | ((TICKS_TO_OFFSET(x) & 0xFFF))) 62 63 #define CYCLE_TIMER_UNWRAP_TICKS(x) (((uint64_t)(x)) \ 64 + (127ULL * TICKS_PER_SECOND) \ 58 65 + (CYCLES_PER_SECOND * TICKS_PER_CYCLE) \ 59 66 + (TICKS_PER_CYCLE) \ 60 67 ) 68 #define CYCLE_TIMER_WRAP_TICKS(x) ((x % TICKS_PER_SECOND)) 61 69 62 #endif // __CYCLE COUNTER_H__70 #endif // __CYCLETIMER_H__ branches/streaming-rework/src/libstreaming/freebob_streaming.cpp
r383 r384 159 159 160 160 // we are ready! 161 162 161 debugOutputShort(DEBUG_LEVEL_VERBOSE, "\n\n"); 163 162 return dev; … … 191 190 debugOutput(DEBUG_LEVEL_VERBOSE,"------------- Start -------------\n"); 192 191 193 194 192 // create the connections for all devices 195 193 // iterate over the found devices … … 207 205 } 208 206 209 dev->processorManager->start(); 210 211 return 0; 207 if(dev->processorManager->start()) { 208 return 0; 209 } else { 210 freebob_streaming_stop(dev); 211 return -1; 212 } 212 213 } 213 214 … … 225 226 assert(device); 226 227 227 228 228 int j=0; 229 229 for(j=0; j<device->getStreamCount();j++) { … … 250 250 static int xruns=0; 251 251 252 periods++; 253 if(periods>periods_print) { 254 debugOutput(DEBUG_LEVEL_VERBOSE, "\n"); 255 debugOutput(DEBUG_LEVEL_VERBOSE, "============================================\n"); 256 debugOutput(DEBUG_LEVEL_VERBOSE, "Xruns: %d\n",xruns); 257 debugOutput(DEBUG_LEVEL_VERBOSE, "============================================\n"); 258 dev->processorManager->dumpInfo(); 259 // debugOutput(DEBUG_LEVEL_VERBOSE, "--------------------------------------------\n"); 260 /* quadlet_t *addr=(quadlet_t*)(dev->processorManager->getPortByIndex(0, Port::E_Capture)->getBufferAddress()); 261 if (addr) hexDumpQuadlets(addr,10);*/ 262 debugOutput(DEBUG_LEVEL_VERBOSE, "\n"); 263 periods_print+=100; 264 } 252 periods++; 253 if(periods>periods_print) { 254 debugOutput(DEBUG_LEVEL_VERBOSE, "\n"); 255 debugOutput(DEBUG_LEVEL_VERBOSE, "============================================\n"); 256 debugOutput(DEBUG_LEVEL_VERBOSE, "Xruns: %d\n",xruns); 257 debugOutput(DEBUG_LEVEL_VERBOSE, "============================================\n"); 258 dev->processorManager->dumpInfo(); 259 debugOutput(DEBUG_LEVEL_VERBOSE, "\n"); 260 periods_print+=100; 261 } 262 265 263 if(dev->processorManager->waitForPeriod()) { 266 264 return dev->options.period_size; 267 265 } else { 268 266 debugWarning("XRUN detected\n"); 267 269 268 // do xrun recovery 270 271 269 dev->processorManager->handleXrun(); 272 270 xruns++; branches/streaming-rework/src/libstreaming/IsoHandler.cpp
r383 r384 29 29 #include "IsoHandler.h" 30 30 #include "IsoStream.h" 31 #include "cyclecounter.h" 32 33 #include "libutil/Time.h" 31 #include "cycletimer.h" 32 34 33 #include "libutil/TimeSource.h" 35 34 #include "libutil/SystemTimeSource.h" … … 39 38 #include <assert.h> 40 39 #include <unistd.h> 40 #include <string.h> 41 41 42 42 #include <iostream> 43 43 using namespace std; 44 44 45 46 #define CC_SLEEP_TIME_AFTER_UPDATE 100 45 #define CC_SLEEP_TIME_AFTER_UPDATE 1000 47 46 #define CC_SLEEP_TIME_AFTER_FAILURE 10 48 #define CC_DLL_COEFF ((0.0 1)*((float)(CC_SLEEP_TIME_AFTER_UPDATE/1000.0)))49 50 #define CC_MAX_RATE_ERROR (2 /100.0)47 #define CC_DLL_COEFF ((0.001)*((float)(CC_SLEEP_TIME_AFTER_UPDATE/1000.0))) 48 49 #define CC_MAX_RATE_ERROR (2.0/100.0) 51 50 #define CC_INIT_MAX_TRIES 10 52 51 … … 96 95 : TimeSource(), m_handle(0), m_handle_util(0), m_port(port), 97 96 m_buf_packets(400), m_max_packet_size(1024), m_irq_interval(-1), 98 m_cycle counter_ticks(0), m_lastmeas_usecs(0), m_ticks_per_usec(24.576),97 m_cycletimer_ticks(0), m_lastmeas_usecs(0), m_ticks_per_usec(24.576), 99 98 m_ticks_per_usec_dll_err2(0), 100 m_packetcount(0), m_dropped(0), m_Client(0) 101 { 102 InitTime(); 99 m_packetcount(0), m_dropped(0), m_Client(0), 100 m_State(E_Created), m_TimeSource_LastSecs(0),m_TimeSource_NbCycleWraps(0) 101 { 103 102 m_TimeSource=new FreebobUtil::SystemTimeSource(); 104 103 } … … 108 107 m_buf_packets(buf_packets), m_max_packet_size( max_packet_size), 109 108 m_irq_interval(irq), 110 m_cycle counter_ticks(0), m_lastmeas_usecs(0), m_ticks_per_usec(24.576),109 m_cycletimer_ticks(0), m_lastmeas_usecs(0), m_ticks_per_usec(24.576), 111 110 m_ticks_per_usec_dll_err2(0), 112 m_packetcount(0), m_dropped(0), m_Client(0) 113 { 114 InitTime(); 111 m_packetcount(0), m_dropped(0), m_Client(0), 112 m_State(E_Created), m_TimeSource_LastSecs(0),m_TimeSource_NbCycleWraps(0) 113 { 115 114 m_TimeSource=new FreebobUtil::SystemTimeSource(); 116 115 } 117 116 118 117 IsoHandler::~IsoHandler() { 118 119 // Don't call until libraw1394's raw1394_new_handle() function has been 120 // fixed to correctly initialise the iso_packet_infos field. Bug is 121 // confirmed present in libraw1394 1.2.1. In any case, 122 // raw1394_destroy_handle() will do any iso system shutdown required. 123 // raw1394_iso_shutdown(m_handle); 124 119 125 if(m_handle) { 126 if (m_State == E_Running) { 120 127 stop(); 128 } 129 121 130 raw1394_destroy_handle(m_handle); 122 131 } 132 123 133 if(m_handle_util) raw1394_destroy_handle(m_handle_util); 124 134 125 delete m_TimeSource;135 if (m_TimeSource) delete m_TimeSource; 126 136 } 127 137 … … 131 141 debugOutput( DEBUG_LEVEL_VERBOSE, "IsoHandler (%p) enter...\n",this); 132 142 143 // check the state 144 if(m_State != E_Created) { 145 debugError("Incorrect state, expected E_Created, got %d\n",(int)m_State); 146 return false; 147 } 148 149 // the main handle for the ISO traffic 133 150 m_handle = raw1394_new_handle_on_port( m_port ); 134 151 if ( !m_handle ) { 135 152 if ( !errno ) { 136 cerr << "libraw1394 not compatible" << endl;153 debugError("libraw1394 not compatible\n"); 137 154 } else { 138 perror( "IsoHandler::Initialize: Could not get 1394 handle");139 cerr << "Is ieee1394 and raw1394 driver loaded?" << endl;155 debugError("Could not get 1394 handle: %s", strerror(errno) ); 156 debugError("Are ieee1394 and raw1394 drivers loaded?"); 140 157 } 141 158 return false; … … 147 164 if ( !m_handle_util ) { 148 165 if ( !errno ) { 149 cerr << "libraw1394 not compatible" << endl;166 debugError("libraw1394 not compatible\n"); 150 167 } else { 151 perror( "IsoHandler::Initialize: Could not get 1394 handle");152 cerr << "Is ieee1394 and raw1394 driver loaded?" << endl;168 debugError("Could not get 1394 handle: %s", strerror(errno) ); 169 debugError("Are ieee1394 and raw1394 drivers loaded?"); 153 170 } 154 return false; 155 } 156 171 172 raw1394_destroy_handle(m_handle); 173 return false; 174 } 157 175 raw1394_set_userdata(m_handle_util, static_cast<void *>(this)); 158 176 177 // bus reset handling 159 178 if(raw1394_busreset_notify (m_handle, RAW1394_NOTIFY_ON)) { 160 179 debugWarning("Could not enable busreset notification.\n"); 161 180 debugWarning(" Error message: %s\n",strerror(errno)); 162 } 163 181 debugWarning("Continuing without bus reset support.\n"); 182 } else { 183 // apparently this cannot fail 164 184 raw1394_set_bus_reset_handler(m_handle, busreset_handler); 185 } 165 186 166 187 // initialize the local timesource 167 188 m_TimeSource_NbCycleWraps=0; 189 unsigned int new_timer; 190 191 #ifdef LIBRAW1394_USE_CTRREAD_API 192 struct raw1394_cycle_timer ctr; 193 int err; 194 err=raw1394_read_cycle_timer(m_handle_util, &ctr); 195 if(err) { 196 debugWarning("raw1394_read_cycle_timer: %s", strerror(err)); 197 } 198 new_timer=ctr.cycle_timer; 199 #else 200 // normally we should be able to use the same handle 201 // because it is not iterated on by any other stuff 202 // but I'm not sure 168 203 quadlet_t buf=0; 169 unsigned int new_counter;170 171 204 raw1394_read(m_handle_util, raw1394_get_local_id(m_handle_util), 172 205 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(); 206 new_timer= ntohl(buf) & 0xFFFFFFFF; 207 #endif 208 209 m_TimeSource_LastSecs=CYCLE_TIMER_GET_SECS(new_timer); 210 211 // update the cycle timer value for initial value 212 initCycleTimer(); 213 214 // update the internal state 215 m_State=E_Initialized; 216 217 return true; 218 } 219 220 bool IsoHandler::prepare() 221 { 222 debugOutput( DEBUG_LEVEL_VERBOSE, "IsoHandler (%p) enter...\n",this); 223 224 // check the state 225 if(m_State != E_Initialized) { 226 debugError("Incorrect state, expected E_Initialized, got %d\n",(int)m_State); 227 return false; 228 } 229 230 // Don't call until libraw1394's raw1394_new_handle() function has been 231 // fixed to correctly initialise the iso_packet_infos field. Bug is 232 // confirmed present in libraw1394 1.2.1. 233 234 // raw1394_iso_shutdown(m_handle); 235 236 m_State = E_Prepared; 237 238 return true; 239 } 240 241 bool IsoHandler::start(int cycle) 242 { 243 debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); 244 245 // check the state 246 if(m_State != E_Prepared) { 247 debugError("Incorrect state, expected E_Prepared, got %d\n",(int)m_State); 248 return false; 249 } 250 251 m_State=E_Running; 252 253 return true; 254 } 255 256 bool IsoHandler::stop() 257 { 258 debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); 259 260 // check state 261 if(m_State != E_Running) { 262 debugError("Incorrect state, expected E_Running, got %d\n",(int)m_State); 263 return false; 264 } 265 266 // this is put here to try and avoid the 267 // Runaway context problem 268 // don't know if it will help though. 269 raw1394_iso_xmit_sync(m_handle); 270 271 raw1394_iso_stop(m_handle); 272 273 m_State=E_Prepared; 179 274 180 275 return true; … … 185 280 { 186 281 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); 282 283 // update the cycle timer value for initial value 284 initCycleTimer(); 285 198 286 return true; 199 287 } … … 210 298 // as busreset can elect a new cycle master, 211 299 // we need to re-initialize our timing code 212 initCycle Counter();300 initCycleTimer(); 213 301 214 302 return 0; … … 216 304 217 305 /** 218 * Returns the current value of the cycle counter (in ticks)219 * 220 * @return the current value of the cycle counter (in ticks)306 * Returns the current value of the cycle timer (in ticks) 307 * 308 * @return the current value of the cycle timer (in ticks) 221 309 */ 222 310 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(); 311 unsigned int IsoHandler::getCycleTimerTicks() { 312 313 #ifdef LIBRAW1394_USE_CTRREAD_API 314 // the new api should be realtime safe. 315 // it might cause a reschedule when turning preemption, 316 // back on but that won't hurt us if we have sufficient 317 // priority 318 struct raw1394_cycle_timer ctr; 319 int err; 320 err=raw1394_read_cycle_timer(m_handle_util, &ctr); 321 if(err) { 322 debugWarning("raw1394_read_cycle_timer: %s", strerror(err)); 323 } 324 return CYCLE_TIMER_TO_TICKS(ctr.cycle_timer); 325 326 #else 327 // use the estimated version 328 freebob_microsecs_t now; 329 now=m_TimeSource->getCurrentTimeAsUsecs(); 330 return mapToCycleTimer(now); 331 #endif 332 333 } 334 335 /** 336 * Returns the current value of the cycle timer (as is) 337 * 338 * @return the current value of the cycle timer (as is) 339 */ 340 341 unsigned int IsoHandler::getCycleTimer() { 342 343 #ifdef LIBRAW1394_USE_CTRREAD_API 344 // the new api should be realtime safe. 345 // it might cause a reschedule when turning preemption, 346 // back on but that won't hurt us if we have sufficient 347 // priority 348 struct raw1394_cycle_timer ctr; 349 int err; 350 err=raw1394_read_cycle_timer(m_handle_util, &ctr); 351 if(err) { 352 debugWarning("raw1394_read_cycle_timer: %s", strerror(err)); 353 } 354 return ctr.cycle_timer; 355 356 #else 357 // use the estimated version 358 freebob_microsecs_t now; 359 now=m_TimeSource->getCurrentTimeAsUsecs(); 360 return TICKS_TO_CYCLE_TIMER(mapToCycleTimer(now)); 361 #endif 362 363 } 364 /** 365 * Maps a value of the active TimeSource to a Cycle Timer value. 366 * 367 * This is usefull if you know a time value and want the corresponding 368 * Cycle Timer value. Note that the value shouldn't be too far off 369 * the current time, because then the mapping can be bad. 370 * 371 * @return the value of the cycle timer (in ticks) 372 */ 373 374 unsigned int IsoHandler::mapToCycleTimer(freebob_microsecs_t now) { 227 375 228 376 // linear interpolation … … 231 379 float offset=m_ticks_per_usec * ((float)delta_usecs); 232 380 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 ); 381 int64_t pred_ticks=(int64_t)m_cycletimer_ticks+(int64_t)offset; 382 383 if (pred_ticks < 0) { 384 debugWarning("Predicted ticks < 0\n"); 385 } 386 debugOutput(DEBUG_LEVEL_VERBOSE,"now=%llu, m_lastmeas_usec=%llu, delta_usec=%d\n", 387 now, m_lastmeas_usecs, delta_usecs); 388 debugOutput(DEBUG_LEVEL_VERBOSE,"t/usec=%f, offset=%f, m_cc_t=%llu, pred_ticks=%lld\n", 389 m_ticks_per_usec, offset, m_cycletimer_ticks, pred_ticks); 238 390 239 391 // if we need to wrap, do it 240 if (pred_ticks > TICKS_PER_SECOND * 128 ) {241 pred_ticks -= TICKS_PER_SECOND * 128 ;392 if (pred_ticks > TICKS_PER_SECOND * 128L) { 393 pred_ticks -= TICKS_PER_SECOND * 128L; 242 394 } 243 395 … … 245 397 } 246 398 247 bool IsoHandler::updateCycleCounter() { 248 quadlet_t buf=0; 249 399 /** 400 * Maps a Cycle Timer value (in ticks) of the active TimeSource's unit. 401 * 402 * This is usefull if you know a Cycle Timer value and want the corresponding 403 * timesource value. Note that the value shouldn't be too far off 404 * the current cycle timer, because then the mapping can be bad. 405 * 406 * @return the mapped value 407 */ 408 409 freebob_microsecs_t IsoHandler::mapToTimeSource(unsigned int cc) { 410 411 // linear interpolation 412 int delta_cc=cc-m_cycletimer_ticks; 413 414 float offset= ((float)delta_cc) / m_ticks_per_usec; 415 416 int64_t pred_time=(int64_t)m_lastmeas_usecs+(int64_t)offset; 417 418 if (pred_time < 0) { 419 debugWarning("Predicted time < 0\n"); 420 debugOutput(DEBUG_LEVEL_VERBOSE,"cc=%u, m_cycletimer_ticks=%llu, delta_cc=%d\n", 421 cc, m_cycletimer_ticks, delta_cc); 422 debugOutput(DEBUG_LEVEL_VERBOSE,"t/usec=%f, offset=%f, m_lastmeas_usecs=%llu, pred_time=%lld\n", 423 m_ticks_per_usec, offset, m_lastmeas_usecs, pred_time); 424 } 425 426 427 return pred_time; 428 } 429 430 bool IsoHandler::updateCycleTimer() { 250 431 freebob_microsecs_t prev_usecs=m_lastmeas_usecs; 251 u nsigned int prev_ticks=m_cyclecounter_ticks;432 uint64_t prev_ticks=m_cycletimer_ticks; 252 433 253 434 freebob_microsecs_t new_usecs; 254 u nsigned int new_ticks;255 unsigned int new_ counter;256 257 /* To estimate the cycle counter, we implement a258 DLL based routine, that maps the cycle counter435 uint64_t new_ticks; 436 unsigned int new_timer; 437 438 /* To estimate the cycle timer, we implement a 439 DLL based routine, that maps the cycle timer 259 440 on the system clock. 260 441 … … 270 451 Basically what we do is estimate the next point (T1,CC1_est) 271 452 based upon the previous point (T0, CC0) and the estimated rate (R). 272 Then we compare our estimation with the measured cycle counter453 Then we compare our estimation with the measured cycle timer 273 454 at T1 (=CC1_meas). We then calculate the estimation error on R: 274 455 err=(CC1_meas-CC0)/(T1-T2) - (CC1_est-CC0)/(T1-T2) … … 288 469 289 470 */ 290 471 #ifdef LIBRAW1394_USE_CTRREAD_API 472 struct raw1394_cycle_timer ctr; 473 int err; 474 err=raw1394_read_cycle_timer(m_handle_util, &ctr); 475 if(err) { 476 debugWarning("raw1394_read_cycle_timer: %s", strerror(err)); 477 } 478 new_usecs=(freebob_microsecs_t)ctr.local_time; 479 new_timer=ctr.cycle_timer; 480 #else 291 481 // normally we should be able to use the same handle 292 482 // because it is not iterated on by any other stuff 293 483 // but I'm not sure 484 quadlet_t buf=0; 294 485 raw1394_read(m_handle_util, raw1394_get_local_id(m_handle_util), 295 486 CSR_REGISTER_BASE | CSR_CYCLE_TIME, 4, &buf); 296 487 new_usecs=m_TimeSource->getCurrentTimeAsUsecs(); 297 298 new_counter= ntohl(buf) & 0xFFFFFFFF; 299 new_ticks=CYCLE_COUNTER_TO_TICKS(new_counter); 488 new_timer= ntohl(buf) & 0xFFFFFFFF; 489 #endif 490 491 new_ticks=CYCLE_TIMER_TO_TICKS(new_timer); 300 492 301 493 // the difference in system time 302 int delta_usecs=new_usecs-prev_usecs;494 int64_t delta_usecs=new_usecs-prev_usecs; 303 495 // this cannot be 0, because m_TimeSource->getCurrentTimeAsUsecs should 304 496 // never return the same value (maybe in future terrahz processors?) 305 497 assert(delta_usecs); 306 498 307 // the measured cycle counter difference308 unsigned int delta_ticks_meas;309 if (new_ticks > prev_ticks) {499 // the measured cycle timer difference 500 int64_t delta_ticks_meas; 501 if (new_ticks >= prev_ticks) { 310 502 delta_ticks_meas=new_ticks - prev_ticks; 311 503 } else { // wraparound 312 delta_ticks_meas=CYCLE_ COUNTER_UNWRAP_TICKS(new_ticks) - prev_ticks;313 } 314 315 // the estimated cycle counter difference316 unsigned int delta_ticks_est=(unsigned int)(m_ticks_per_usec * ((float)delta_usecs));504 delta_ticks_meas=CYCLE_TIMER_UNWRAP_TICKS(new_ticks) - prev_ticks; 505 } 506 507 // the estimated cycle timer difference 508 int64_t delta_ticks_est=(int64_t)(m_ticks_per_usec * ((float)delta_usecs)); 317 509 318 510 // the measured & estimated rate 319 float rate_meas=(( float)delta_ticks_meas/(float)delta_usecs);511 float rate_meas=((double)delta_ticks_meas/(double)delta_usecs); 320 512 float rate_est=((float)m_ticks_per_usec); 321 513 … … 338 530 #ifdef DEBUG 339 531 340 int diff=(int)delta_ticks_est;532 int64_t diff=(int64_t)delta_ticks_est; 341 533 342 534 // calculate the difference in predicted ticks and … … 345 537 346 538 347 if (diff > 24000 || diff < -24000) { // approx +/-1 msec error348 debugOutput(DEBUG_LEVEL_VERBOSE,"Bad pred (%p): diff=% d, dt_est=%u, dt_meas=%u, d=%dus, err=%fus\n", this,539 if (diff > 24000L || diff < -24000L) { // approx +/-1 msec error 540 debugOutput(DEBUG_LEVEL_VERBOSE,"Bad pred (%p): diff=%lld, dt_est=%lld, dt_meas=%lld, d=%lldus, err=%fus\n", this, 349 541 diff, delta_ticks_est, delta_ticks_meas, delta_usecs, (((float)diff)/24.576) 350 542 ); 351 543 } else { 352 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Good pred: diff=% d, dt_est=%u, dt_meas=%u, d=%dus, err=%fus\n",544 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Good pred: diff=%lld, dt_est=%lld, dt_meas=%lld, d=%lldus, err=%fus\n", 353 545 diff, delta_ticks_est, delta_ticks_meas, delta_usecs, (((float)diff)/24.576) 354 546 ); … … 379 571 380 572 // update the internal values 381 // note: the next cycle counter point is573 // note: the next cycletimer point is 382 574 // the estimated one, not the measured one! 383 m_cycle counter_ticks += delta_ticks_est;575 m_cycletimer_ticks += delta_ticks_est; 384 576 // if we need to wrap, do it 385 if (m_cycle counter_ticks > TICKS_PER_SECOND * 128) {386 m_cycle counter_ticks -= TICKS_PER_SECOND * 128;577 if (m_cycletimer_ticks > TICKS_PER_SECOND * 128L) { 578 m_cycletimer_ticks -= TICKS_PER_SECOND * 128L; 387 579 } 388 580 389 581 m_lastmeas_usecs = new_usecs; 390 582 391 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"U TS: %10 u -> %10u, d=%7uus, dt_est=%7u, dt_meas=%7u, erate=%6.4f, mrate=%6f\n",392 prev_ticks, m_cycle counter_ticks, delta_usecs,583 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"U TS: %10llu -> %10llu, d=%7lldus, dt_est=%7lld, dt_meas=%7lld, erate=%6.4f, mrate=%6f\n", 584 prev_ticks, m_cycletimer_ticks, delta_usecs, 393 585 delta_ticks_est, delta_ticks_meas, m_ticks_per_usec, rate_meas 394 586 ); … … 405 597 } 406 598 407 void IsoHandler::initCycleCounter() { 408 quadlet_t buf=0; 409 599 void IsoHandler::initCycleTimer() { 410 600 freebob_microsecs_t prev_usecs; 411 601 unsigned int prev_ticks; 412 unsigned int prev_ counter;602 unsigned int prev_timer; 413 603 414 604 freebob_microsecs_t new_usecs; 415 605 unsigned int new_ticks; 416 unsigned int new_ counter;606 unsigned int new_timer; 417 607 418 608 float rate=0.0; … … 428 618 || (rate < 24.576*(1.0-CC_MAX_RATE_ERROR)))) { 429 619 620 #ifdef LIBRAW1394_USE_CTRREAD_API 621 struct raw1394_cycle_timer ctr; 622 int err; 623 err=raw1394_read_cycle_timer(m_handle_util, &ctr); 624 if(err) { 625 debugWarning("raw1394_read_cycle_timer: %s", strerror(err)); 626 } 627 prev_usecs=(freebob_microsecs_t)ctr.local_time; 628 prev_timer=ctr.cycle_timer; 629 #else 430 630 // normally we should be able to use the same handle 431 631 // because it is not iterated on by any other stuff 432 632 // but I'm not sure 633 quadlet_t buf=0; 433 634 raw1394_read(m_handle_util, raw1394_get_local_id(m_handle_util), 434 635 CSR_REGISTER_BASE | CSR_CYCLE_TIME, 4, &buf); 435 636 prev_usecs=m_TimeSource->getCurrentTimeAsUsecs(); 436 437 prev_counter= ntohl(buf) & 0xFFFFFFFF; 438 prev_ticks=CYCLE_ COUNTER_TO_TICKS(prev_counter);637 prev_timer= ntohl(buf) & 0xFFFFFFFF; 638 #endif 639 prev_ticks=CYCLE_TIMER_TO_TICKS(prev_timer); 439 640 440 641 usleep(CC_SLEEP_TIME_AFTER_UPDATE); 441 642 643 644 #ifdef LIBRAW1394_USE_CTRREAD_API 645 err=raw1394_read_cycle_timer(m_handle_util, &ctr); 646 if(err) { 647 debugWarning("raw1394_read_cycle_timer: %s", strerror(err)); 648 } 649 new_usecs=(freebob_microsecs_t)ctr.local_time; 650 new_timer=ctr.cycle_timer; 651 #else 442 652 // normally we should be able to use the same handle 443 653 // because it is not iterated on by any other stuff … … 446 656 CSR_REGISTER_BASE | CSR_CYCLE_TIME, 4, &buf); 447 657 new_usecs=m_TimeSource->getCurrentTimeAsUsecs(); 448 449 new_counter= ntohl(buf) & 0xFFFFFFFF; 450 new_ticks=CYCLE_COUNTER_TO_TICKS(new_counter); 658 new_timer= ntohl(buf) & 0xFFFFFFFF; 659 #endif 660 661 new_ticks=CYCLE_TIMER_TO_TICKS(new_timer); 451 662 452 663 unsigned int delta_ticks; … … 455 666 delta_ticks=new_ticks - prev_ticks; 456 667 } else { // wraparound 457 delta_ticks=CYCLE_ COUNTER_UNWRAP_TICKS(new_ticks) - prev_ticks;668 delta_ticks=CYCLE_TIMER_UNWRAP_TICKS(new_ticks) - prev_ticks; 458 669 } 459 670 … … 467 678 468 679 // update the internal values 469 m_cycle counter_ticks=new_ticks;680 m_cycletimer_ticks=new_ticks; 470 681 m_lastmeas_usecs=new_usecs; 471 682 … … 478 689 // this is not fatal, the DLL will eventually correct this 479 690 if(try_cnt == CC_INIT_MAX_TRIES) { 480 debugWarning("Failed to properly initialize cycle counter...\n");691 debugWarning("Failed to properly initialize cycle timer...\n"); 481 692 } 482 693 … … 495 706 debugOutputShort( DEBUG_LEVEL_NORMAL, " Handler type : %s\n", 496 707 (this->getType()==EHT_Receive ? "Receive" : "Transmit")); 497 debugOutputShort( DEBUG_LEVEL_NORMAL, " Port, Channel : %2d, %2d\n",708 debugOutputShort( DEBUG_LEVEL_NORMAL, " Port, Channel : %2d, %2d\n", 498 709 m_port, channel); 499 debugOutputShort( DEBUG_LEVEL_NORMAL, " Packet count : %10d (%5d dropped)\n",710 debugOutputShort( DEBUG_LEVEL_NORMAL, " Packet count : %10d (%5d dropped)\n", 500 711 this->getPacketCount(), this->getDroppedCount()); 712 501 713 #ifdef DEBUG 502 unsigned int cc=this->getCycle Counter();503 debugOutputShort( DEBUG_LEVEL_NORMAL, " Cycle counter: %10lu (%03us, %04ucycles, %04uticks)\n",714 unsigned int cc=this->getCycleTimerTicks(); 715 debugOutputShort( DEBUG_LEVEL_NORMAL, " Cycle timer : %10lu (%03us, %04ucycles, %04uticks)\n", 504 716 cc,TICKS_TO_SECS(cc),TICKS_TO_CYCLES(cc),TICKS_TO_OFFSET(cc)); 717 718 /* freebob_microsecs_t now=m_TimeSource->getCurrentTimeAsUsecs(); 719 cc=mapToCycleTimer(now); 720 freebob_microsecs_t now_mapped=mapToTimeSource(cc); 721 722 debugOutputShort( DEBUG_LEVEL_NORMAL, " Mapping test : now: %14llu, cc: %10lu, mapped now: %14llu\n", 723 now,cc,now_mapped);*/ 505 724 #endif 506 debugOutputShort( DEBUG_LEVEL_NORMAL, " Ticks/usec : %8.6f (dll2: %8.6e)\n\n",725 debugOutputShort( DEBUG_LEVEL_NORMAL, " Ticks/usec : %8.6f (dll2: %8.6e)\n\n", 507 726 this->getTicksPerUsec(), m_ticks_per_usec_dll_err2); 508 727 … … 551 770 /* The timesource interface */ 552 771 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; 772 unsigned int new_timer; 773 774 new_timer= getCycleTimerTicks(); 560 775 561 776 // this assumes that it never happens that there are more than 2 562 777 // minutes between calls 563 if (CYCLE_ COUNTER_GET_SECS(new_counter) < m_TimeSource_LastSecs) {778 if (CYCLE_TIMER_GET_SECS(new_timer) < m_TimeSource_LastSecs) { 564 779 m_TimeSource_NbCycleWraps++; 565 780 } 566 781 567 freebob_microsecs_t ticks=m_TimeSource_NbCycleWraps * 128 * TICKS_PER_SECOND568 + CYCLE_ COUNTER_TO_TICKS(new_counter);569 570 m_TimeSource_LastSecs=CYCLE_ COUNTER_GET_SECS(new_counter);782 freebob_microsecs_t ticks=m_TimeSource_NbCycleWraps * 128L * TICKS_PER_SECOND 783 + CYCLE_TIMER_TO_TICKS(new_timer); 784 785 m_TimeSource_LastSecs=CYCLE_TIMER_GET_SECS(new_timer); 571 786 572 787 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Wraps=%4u, LastSecs=%3u, nowSecs=%3u, ticks=%10u\n", 573 788 m_TimeSource_NbCycleWraps, m_TimeSource_LastSecs, 574 CYCLE_ COUNTER_GET_SECS(new_counter), ticks789 CYCLE_TIMER_GET_SECS(new_timer), ticks 575 790 ); 576 791 577 792 return ticks; 793 } 794 795 freebob_microsecs_t IsoHandler::unWrapTime(freebob_microsecs_t t) { 796 return CYCLE_TIMER_UNWRAP_TICKS(t); 797 } 798 799 freebob_microsecs_t IsoHandler::wrapTime(freebob_microsecs_t t) { 800 return CYCLE_TIMER_WRAP_TICKS(t); 578 801 } 579 802 … … 608 831 IsoRecvHandler::~IsoRecvHandler() 609 832 { 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; 833 617 834 } 618 835 … … 628 845 } 629 846 630 enum raw1394_iso_disposition IsoRecvHandler::putPacket(unsigned char *data, unsigned int length, 847 enum raw1394_iso_disposition IsoRecvHandler::putPacket( 848 unsigned char *data, unsigned int length, 631 849 unsigned char channel, unsigned char tag, unsigned char sy, 632 850 unsigned int cycle, unsigned int dropped) { … … 647 865 bool IsoRecvHandler::prepare() 648 866 { 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); 867 868 // prepare the generic IsoHandler 869 if(!IsoHandler::prepare()) { 870 return false; 871 } 653 872 654 873 debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing iso receive handler (%p)\n",this); … … 658 877 debugOutput( DEBUG_LEVEL_VERBOSE, " Irq interval : %d \n",m_irq_interval); 659 878 660 if(raw1394_iso_recv_init(m_handle, iso_receive_handler, 879 if(raw1394_iso_recv_init(m_handle, 880 iso_receive_handler, 661 881 m_buf_packets, 662 882 m_max_packet_size, … … 676 896 debugOutput( DEBUG_LEVEL_VERBOSE, "start on cycle %d\n", cycle); 677 897 898 // start the generic IsoHandler 899 if(!IsoHandler::start(cycle)) { 900 return false; 901 } 902 678 903 if(raw1394_iso_recv_start(m_handle, cycle, -1, 0)) { 679 904 debugFatal("Could not start receive handler (%s)\n",strerror(errno)); … … 723 948 IsoXmitHandler::~IsoXmitHandler() 724 949 { 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; 950 // handle cleanup is done in the IsoHanlder destructor 732 951 } 733 952 … … 742 961 743 962 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 963 } 763 964 … … 766 967 debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing iso transmit handler (%p, client=%p)\n",this,m_Client); 767 968 768 // raw1394_iso_shutdown(m_handle); 969 if(!(IsoHandler::prepare())) { 970 return false; 971 } 972 769 973 debugOutput( DEBUG_LEVEL_VERBOSE, " Buffers : %d \n",m_buf_packets); 770 974 debugOutput( DEBUG_LEVEL_VERBOSE, " Max Packet size : %d \n",m_max_packet_size); … … 791 995 { 792 996 debugOutput( DEBUG_LEVEL_VERBOSE, "start on cycle %d\n", cycle); 997 998 if(!(IsoHandler::start(cycle))) { 999 return false; 1000 } 1001 793 1002 if(raw1394_iso_xmit_start(m_handle, cycle, m_prebuffers)) { 794 1003 debugFatal("Could not start xmit handler (%s)\n",strerror(errno)); … … 796 1005 } 797 1006 return true; 1007 } 1008 1009 enum raw1394_iso_disposition IsoXmitHandler::getPacket( 1010 unsigned char *data, unsigned int *length, 1011 unsigned char *tag, unsigned char *sy, 1012 int cycle, unsigned int dropped) { 1013 1014 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, 1015 "sending packet: length=%d, cycle=%d\n", 1016 *length, cycle ); 1017 m_packetcount++; 1018 m_dropped+=dropped; 1019 1020 if(m_Client) { 1021 return m_Client->getPacket(data, length, tag, sy, cycle, dropped, m_max_packet_size); 1022 } 1023 1024 return RAW1394_ISO_OK; 798 1025 } 799 1026 branches/streaming-rework/src/libstreaming/IsoHandler.h
r383 r384 68 68 69 69 virtual bool init(); 70 virtual bool prepare(); 71 virtual bool start(int cycle); 72 virtual bool stop(); 70 73 71 74 int iterate() { if(m_handle) return raw1394_loop_iterate(m_handle); else return -1; }; … … 86 89 virtual enum EHandlerType getType() = 0; 87 90 88 virtual bool start(int cycle) = 0;89 virtual bool stop();90 91 91 int getFileDescriptor() { return raw1394_get_fd(m_handle);}; 92 92 … … 102 102 int getPort() {return m_port;}; 103 103 104 virtual bool prepare() = 0; 105 106 // get the most recent cycle counter value 107 // RT safe 108 unsigned int getCycleCounter(); 109 110 // update the cycle counter cache 111 // not RT safe 112 // the isohandlermanager is responsible for calling this! 113 bool updateCycle Counter();104 /// get the most recent cycle timer value (in ticks) 105 unsigned int getCycleTimerTicks(); 106 /// get the most recent cycle timer value (as is) 107 unsigned int getCycleTimer(); 108 /// Maps a value of the active TimeSource to a Cycle Timer value. 109 unsigned int mapToCycleTimer(freebob_microsecs_t now); 110 /// Maps a Cycle Timer value to the active TimeSource's unit. 111 freebob_microsecs_t mapToTimeSource(unsigned int cc); 112 /// update the cycle timer cache 113 bool updateCycleTimer(); 114 114 float getTicksPerUsec() {return m_ticks_per_usec;}; 115 115 … … 125 125 int m_irq_interval; 126 126 127 unsigned int m_cyclecounter_ticks;128 freebob_microsecs_t m_lastmeas_usecs;127 uint64_t m_cycletimer_ticks; 128 uint64_t m_lastmeas_usecs; 129 129 float m_ticks_per_usec; 130 130 float m_ticks_per_usec_dll_err2; … … 145 145 static int busreset_handler(raw1394handle_t handle, unsigned int generation); 146 146 147 void initCycleCounter(); 147 void initCycleTimer(); 148 149 // the state machine 150 private: 151 enum EHandlerStates { 152 E_Created, 153 E_Initialized, 154 E_Prepared, 155 E_Running, 156 E_Error 157 }; 158 159 enum EHandlerStates m_State; 148 160 149 161 // implement the TimeSource interface … … 151 163 freebob_microsecs_t getCurrentTime(); 152 164 freebob_microsecs_t getCurrentTimeAsUsecs(); 165 inline freebob_microsecs_t unWrapTime(freebob_microsecs_t t); 166 inline freebob_microsecs_t wrapTime(freebob_microsecs_t t); 167 153 168 private: 154 169 // to cope with wraparound … … 173 188 174 189 enum EHandlerType getType() { return EHT_Receive;}; 175 176 // int registerStream(IsoStream *);177 // int unregisterStream(IsoStream *);178 190 179 191 bool start(int cycle); … … 216 228 217 229 enum EHandlerType getType() { return EHT_Transmit;}; 218 219 // int registerStream(IsoStream *);220 // int unregisterStream(IsoStream *);221 230 222 231 unsigned int getPreBuffers() {return m_prebuffers;}; branches/streaming-rework/src/libstreaming/IsoHandlerManager.cpp
r383 r384 32 32 #include <assert.h> 33 33 34 35 34 namespace FreebobStreaming 36 35 { … … 39 38 40 39 IsoHandlerManager::IsoHandlerManager() : 41 m_poll_timeout(100), m_poll_fds(0), m_poll_nfds(0) 40 m_State(E_Created), 41 m_poll_timeout(1), m_poll_fds(0), m_poll_nfds(0) 42 42 { 43 43 … … 57 57 } 58 58 59 // the IsoHandlerManager thread updates the handler caches 60 // it doesn't iterate them !!! 59 /** 60 * the IsoHandlerManager thread execute function iterates the handlers. 61 * 62 * This means that once the thread is running, streams are 63 * transmitted and received (if present on the bus). Make sure 64 * that the clients are registered & ready before starting the 65 * thread! 66 * 67 * The register and unregister functions are thread unsafe, so 68 * should not be used when the thread is running. 69 * 70 * @return false if the handlers could not be iterated. 71 */ 61 72 bool IsoHandlerManager::Execute() 62 73 { 63 updateCycleCounters(); 64 usleep(USLEEP_AFTER_UPDATE); 74 // updateCycleTimers(); 75 76 if(!iterate()) { 77 debugFatal("Could not iterate the isoManager\n"); 78 return false; 79 } 65 80 66 81 return true; 67 82 } 68 83 84 /** 85 * Poll the handlers managed by this manager, and iterate them 86 * when ready 87 * 88 * @return true when successful 89 */ 69 90 bool IsoHandlerManager::iterate() 70 91 { … … 104 125 } 105 126 106 // updates the internal cycle counter caches of the handlers107 void IsoHandlerManager::updateCycle Counters() {127 // updates the internal cycle timer caches of the handlers 128 void IsoHandlerManager::updateCycleTimers() { 108 129 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "enter...\n"); 109 130 … … 113 134 { 114 135 int cnt=0; 115 while (!(*it)->updateCycle Counter() && (cnt++ < MAX_UPDATE_TRIES)) {136 while (!(*it)->updateCycleTimer() && (cnt++ < MAX_UPDATE_TRIES)) { 116 137 usleep(USLEEP_AFTER_UPDATE_FAILURE); 117 138 } … … 119 140 120 141 } 121 122 bool IsoHandlerManager::prepare()123 {124 debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");125 for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();126 it != m_IsoHandlers.end();127 ++it )128 {129 if(!(*it)->prepare()) {130 debugFatal("Could not prepare handlers\n");131 return false;132 }133 }134 135 return true;136 }137 138 139 142 140 143 bool IsoHandlerManager::registerHandler(IsoHandler *handler) … … 205 208 206 209 void IsoHandlerManager::disablePolling(IsoStream *stream) { 210 int i=0; 211 207 212 debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Disable polling on stream %p\n",stream); 208 int i=0; 213 209 214 for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); 210 215 it != m_IsoHandlers.end(); … … 216 221 debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "polling disabled\n"); 217 222 } 223 218 224 i++; 219 225 } 220 221 226 } 222 227 223 228 void IsoHandlerManager::enablePolling(IsoStream *stream) { 229 int i=0; 230 224 231 debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Enable polling on stream %p\n",stream); 225 int i=0;232 226 233 for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); 227 234 it != m_IsoHandlers.end(); … … 233 240 debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "polling enabled\n"); 234 241 } 242 235 243 i++; 236 244 } … … 478 486 } 479 487 488 489 bool IsoHandlerManager::prepare() 490 { 491 bool retval=true; 492 493 debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); 494 495 // check state 496 if(m_State != E_Created) { 497 debugError("Incorrect state, expected E_Created, got %d\n",(int)m_State); 498 return false; 499 } 500 501 for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); 502 it != m_IsoHandlers.end(); 503 ++it ) 504 { 505 if(!(*it)->prepare()) { 506 debugFatal("Could not prepare handlers\n"); 507 retval=false; 508 } 509 } 510 511 if (retval) { 512 m_State=E_Prepared; 513 } else { 514 m_State=E_Error; 515 } 516 517 return retval; 518 } 519 480 520 bool IsoHandlerManager::startHandlers() { 481 521 return startHandlers(-1); … … 483 523 484 524 bool IsoHandlerManager::startHandlers(int cycle) { 525 bool retval=true; 526 485 527 debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); 528 529 // check state 530 if(m_State != E_Prepared) { 531 debugError("Incorrect state, expected E_Prepared, got %d\n",(int)m_State); 532 return false; 533 } 486 534 487 535 for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); … … 492 540 if(!(*it)->start(cycle)) { 493 541 debugOutput( DEBUG_LEVEL_VERBOSE, " could not start handler (%p)\n",*it); 494 returnfalse;542 retval=false; 495 543 } 496 544 } 497 545 498 return true; 546 if (retval) { 547 m_State=E_Running; 548 } else { 549 m_State=E_Error; 550 } 551 552 return retval; 499 553 } 500 554 501 555 bool IsoHandlerManager::stopHandlers() { 502 556 debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); 557 558 // check state 559 if(m_State != E_Running) { 560 debugError("Incorrect state, expected E_Running, got %d\n",(int)m_State); 561 return false; 562 } 563 564 bool retval=true; 503 565 504 566 for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); … … 509 571 if(!(*it)->stop()){ 510 572 debugOutput( DEBUG_LEVEL_VERBOSE, " could not stop handler (%p)\n",*it); 511 returnfalse;573 retval=false; 512 574 } 513 575 } 514 return true; 515 } 576 577 if (retval) { 578 m_State=E_Prepared; 579 } else { 580 m_State=E_Error; 581 } 582 583 return retval; 584 } 585 586 bool IsoHandlerManager::reset() { 587 debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); 588 589 // check state 590 if(m_State == E_Error) { 591 debugFatal("Resetting from error condition not yet supported...\n"); 592 return false; 593 } 594 595 // if not in an error condition, reset means stop the handlers 596 return stopHandlers(); 597 } 598 516 599 517 600 void IsoHandlerManager::setVerboseLevel(int i) { … … 527 610 528 611 void IsoHandlerManager::dumpInfo() { 529 debugOutputShort( DEBUG_LEVEL_NORMAL, "Dumping IsoHandlerManager Stream handler information...\n");530 612 int i=0; 531 613 614 debugOutputShort( DEBUG_LEVEL_NORMAL, "Dumping IsoHandlerManager Stream handler information...\n"); 615 debugOutputShort( DEBUG_LEVEL_NORMAL, " State: %d\n",(int)m_State); 616 532 617 for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); 533 618 it != m_IsoHandlers.end(); branches/streaming-rework/src/libstreaming/IsoHandlerManager.h
r383 r384 89 89 bool stopHandlers(); ///< stop the managed ISO handlers 90 90 91 bool reset() {return true;}; ///< reset the ISO manager and all streams91 bool reset(); ///< reset the ISO manager and all streams 92 92 93 93 bool prepare(); ///< prepare the ISO manager and all streams … … 96 96 void enablePolling(IsoStream *); ///< enables polling on a stream 97 97 98 public:99 100 101 98 // RunnableInterface interface 99 public: 102 100 bool Execute(); // note that this is called in we while(running) loop 103 101 bool Init(); 104 102 105 // iterate all handlers 106 bool iterate(); 103 // the state machine 107 104 private: 108 // updates the cycle counter caches of all handlers 109 void updateCycleCounters(); 105 enum EHandlerStates { 106 E_Created, 107 E_Prepared, 108 E_Running, 109 E_Error 110 }; 110 111 112 enum EHandlerStates m_State; 113 114 private: 115 /// iterate all child handlers 116 bool iterate(); 117 public: // FIXME: just so that SPM can do this (temp solution) 118 /// updates the cycle timer caches of all child handlers 119 void updateCycleTimers(); 120 private: 111 121 // note: there is a disctinction between streams and handlers 112 122 // because one handler can serve multiple streams (in case of … … 134 144 bool rebuildFdMap(); 135 145 136 146 // debug stuff 137 147 DECLARE_DEBUG_MODULE; 138 148 branches/streaming-rework/src/libstreaming/IsoStream.cpp
r383 r384 30 30 #include "PacketBuffer.h" 31 31 #include <assert.h> 32 33 32 34 33 namespace FreebobStreaming … … 83 82 m_port, m_channel); 84 83 85 } ;84 } 86 85 87 86 bool IsoStream::setChannel(int c) { branches/streaming-rework/src/libstreaming/MotuStreamProcessor.cpp
r383 r384 28 28 */ 29 29 30 #ifdef ENABLE_MOTU 30 31 31 32 #include "MotuStreamProcessor.h" … … 101 102 m_running = true; 102 103 103 // Initialise the cycle counter if this is the first time104 // Initialise the cycle timer if this is the first time 104 105 // iso data has been requested. 105 106 if (!m_disabled && m_cycle_count<0) { … … 176 177 m_next_cycle -= 8000; 177 178 178 // Deal cleanly with potential wrap-around cycle counter conditions179 // Deal cleanly with potential wrap-around cycle timer conditions 179 180 unwrapped_cycle = cycle; 180 181 if (m_cycle_count-cycle > 7900) … … 843 844 } 844 845 845 bool MotuTransmitStreamProcessor::prepare dForStop() {846 bool MotuTransmitStreamProcessor::prepareForStop() { 846 847 847 848 // If the stream is disabled or isn't running there's no need to … … 894 895 } 895 896 896 bool MotuTransmitStreamProcessor::prepare dForStart() {897 bool MotuTransmitStreamProcessor::prepareForStart() { 897 898 // Reset some critical variables required so the stream starts cleanly. This 898 899 // method is called once on every stream restart, including those during … … 1523 1524 } 1524 1525 1525 bool MotuReceiveStreamProcessor::prepare dForStop() {1526 bool MotuReceiveStreamProcessor::prepareForStop() { 1526 1527 1527 1528 // A MOTU receive stream can stop at any time. However, signify … … 1535 1536 } 1536 1537 1537 bool MotuReceiveStreamProcessor::prepare dForStart() {1538 bool MotuReceiveStreamProcessor::prepareForStart() { 1538 1539 // Reset some critical variables required so the stream starts cleanly. This 1539 1540 // method is called once on every stream restart, including those during … … 1556 1557 1557 1558 } // end of namespace FreebobStreaming 1559 #endif branches/streaming-rework/src/libstreaming/MotuStreamProcessor.h
r312 r384 35 35 36 36 #include "../libutil/DelayLockedLoop.h" 37 38 #ifdef ENABLE_MOTU 37 39 38 40 namespace FreebobStreaming { … … 75 77 void setTicksPerFrameDLL(float *dll) {m_ticks_per_frame=dll;}; 76 78 77 virtual bool prepare dForStop();78 virtual bool prepare dForStart();79 virtual bool prepareForStop(); 80 virtual bool prepareForStart(); 79 81 80 82 protected: … … 165 167 unsigned int getEventSize(void); 166 168 167 virtual bool prepare dForStop();168 virtual bool prepare dForStart();169 virtual bool prepareForStop(); 170 virtual bool prepareForStart(); 169 171 170 172 protected: … … 183 185 unsigned int m_event_size; 184 186 185 // The integrator of a Delay-Locked Loop (DLL) used to provide a186 // continuously updated estimate of the number of ieee1394 frames187 // per audio frame at the current sample rate.188 float m_ticks_per_frame;189 190 187 signed int m_last_cycle_ofs; 191 188 signed int m_next_cycle; … … 201 198 } // end of namespace FreebobStreaming 202 199 200 #endif /* ENABLE_MOTU */ 201 203 202 #endif /* __FREEBOB_MOTUSTREAMPROCESSOR__ */ 204 203 branches/streaming-rework/src/libstreaming/StreamProcessor.cpp
r383 r384 46 46 , m_framecounter(0) 47 47 , m_framerate(framerate) 48 , m_manager(0) 48 , m_manager(NULL) 49 , m_SyncSource(NULL) 50 , m_ticks_per_frame(0) 49 51 , m_running(false) 50 52 , m_disabled(true) … … 69 71 debugOutputShort( DEBUG_LEVEL_NORMAL, " Enabled : %d\n", !m_disabled); 70 72 71 m_PeriodStat.dumpInfo(); 72 m_PacketStat.dumpInfo(); 73 m_WakeupStat.dumpInfo(); 74 75 73 // m_PeriodStat.dumpInfo(); 74 // m_PacketStat.dumpInfo(); 75 // m_WakeupStat.dumpInfo(); 76 76 77 } 77 78 … … 80 81 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "enter...\n"); 81 82 83 pthread_mutex_init(&m_framecounter_lock, NULL); 84 82 85 return IsoStream::init(); 83 86 } … … 138 141 } 139 142 140 bool StreamProcessor::transfer() { 141 142 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Transferring period...\n"); 143 // TODO: implement 144 143 /** 144 * @brief Notify the StreamProcessor that frames were written 145 * 146 * This notifies the StreamProcessor of the fact that frames were written to the internal 147 * buffer. This is for framecounter & timestamp bookkeeping. 148 * 149 * @param nbframes the number of frames that are written to the internal buffers 150 * @param ts the new timestamp of the 'tail' of the buffer, i.e. the last sample 151 * present in the buffer. 152 * @return true if successful 153 */ 154 bool StreamProcessor::putFrames(unsigned int nbframes, int64_t ts) { 155 156 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Putting %d frames for %llu into frame buffer...\n", nbframes,ts); 157 incrementFrameCounter(nbframes, ts); 158 return true; 159 } 160 161 /** 162 * @brief Notify the StreamProcessor that frames were read 163 * 164 * This notifies the StreamProcessor of the fact that frames were read from the internal 165 * buffer. This is for framecounter & timestamp bookkeeping. 166 * 167 * @param nbframes the number of frames that are read from the internal buffers 168 * @param ts the new timestamp of the 'head' of the buffer, i.e. the first sample 169 * present in the buffer. 170 * @return true if successful 171 */ 172 bool StreamProcessor::getFrames(unsigned int nbframes, int64_t ts) { 173 174 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Getting %d frames from frame buffer...\n", nbframes); 175 decrementFrameCounter(nbframes, ts); 145 176 return true; 146 177 } … … 157 188 } 158 189 190 bool StreamProcessor::setSyncSource(StreamProcessor *s) { 191 m_SyncSource=s; 192 return true; 193 } 194 159 195 /** 160 196 * Decrements the frame counter, in a atomic way. This 197 * also sets the buffer tail timestamp 161 198 * is thread safe. 162 199 */ 163 void StreamProcessor::decrementFrameCounter() { 164 SUBSTRACT_ATOMIC((SInt32 *)&m_framecounter,m_period); 165 } 166 /** 167 * Increments the frame counter, in a atomic way. This 168 * is thread safe. 169 */ 170 void StreamProcessor::incrementFrameCounter(int nbframes) { 171 ADD_ATOMIC((SInt32 *)&m_framecounter, nbframes); 200 void StreamProcessor::decrementFrameCounter(int nbframes, uint64_t new_timestamp) { 201 pthread_mutex_lock(&m_framecounter_lock); 202 m_framecounter -= nbframes; 203 m_buffer_head_timestamp = new_timestamp; 204 pthread_mutex_unlock(&m_framecounter_lock); 205 } 206 207 /** 208 * Increments the frame counter, in a atomic way. 209 * also sets the buffer head timestamp 210 * This is thread safe. 211 */ 212 void StreamProcessor::incrementFrameCounter(int nbframes, uint64_t new_timestamp) { 213 pthread_mutex_lock(&m_framecounter_lock); 214 m_framecounter += nbframes; 215 m_buffer_tail_timestamp = new_timestamp; 216 pthread_mutex_unlock(&m_framecounter_lock); 217 218 } 219 220 /** 221 * Sets the frame counter, in a atomic way. 222 * also sets the buffer head timestamp 223 * This is thread safe. 224 */ 225 void StreamProcessor::setFrameCounter(int new_framecounter, uint64_t new_timestamp) { 226 pthread_mutex_lock(&m_framecounter_lock); 227 m_framecounter = new_framecounter; 228 m_buffer_tail_timestamp = new_timestamp; 229 pthread_mutex_unlock(&m_framecounter_lock); 230 } 231 232 /** 233 * Sets the buffer tail timestamp (in usecs) 234 * This is thread safe. 235 */ 236 void StreamProcessor::setBufferTailTimestamp(uint64_t new_timestamp) { 237 pthread_mutex_lock(&m_framecounter_lock); 238 m_buffer_tail_timestamp = new_timestamp; 239 pthread_mutex_unlock(&m_framecounter_lock); 240 } 241 242 /** 243 * Sets the buffer head timestamp (in usecs) 244 * This is thread safe. 245 */ 246 void StreamProcessor::setBufferHeadTimestamp(uint64_t new_timestamp) { 247 pthread_mutex_lock(&m_framecounter_lock); 248 m_buffer_head_timestamp = new_timestamp; 249 pthread_mutex_unlock(&m_framecounter_lock); 250 } 251 252 /** 253 * Sets both the buffer head and tail timestamps (in usecs) 254 * (avoids multiple mutex lock/unlock's) 255 * This is thread safe. 256 */ 257 void StreamProcessor::setBufferTimestamps(uint64_t new_head, uint64_t new_tail) { 258 pthread_mutex_lock(&m_framecounter_lock); 259 m_buffer_head_timestamp = new_head; 260 m_buffer_tail_timestamp = new_tail; 261 pthread_mutex_unlock(&m_framecounter_lock); 262 } 263 /** 264 * \brief return the timestamp of the first frame in the buffer 265 * 266 * This function returns the timestamp of the very first sample in 267 * the StreamProcessor's buffer. This is useful for slave StreamProcessors 268 * to find out what the base for their timestamp generation should 269 * be. It also returns the framecounter value for which this timestamp 270 * is valid. 271 * 272 * The system is built in such a way that we assume that the processing 273 * of the buffers doesn't take any time. Assume we have a buffer transfer at 274 * time T1, meaning that the last sample of this buffer occurs at T1. As 275 * processing does not take time, we don't have to add anything to T1. When 276 * transferring the processed buffer to the xmit processor, the timestamp 277 * of the last sample is still T1. 278 * 279 * When starting the streams, we don't have any information on this last 280 * timestamp. We prefill the buffer at the xmit side, and we should find 281 * out what the timestamp for the last sample in the buffer is. If we sync 282 * on a receive SP, we know that the last prefilled sample corresponds with 283 * the first sample received - 1 sample duration. This is the same as if the last 284 * transfer from iso to client would have emptied the receive buffer. 285 * 286 * 287 * @param ts address to store the timestamp in 288 * @param fc address to store the associated framecounter in 289 */ 290 void StreamProcessor::getBufferHeadTimestamp(uint64_t *ts, uint64_t *fc) { 291 pthread_mutex_lock(&m_framecounter_lock); 292 *fc = m_framecounter; 293 *ts = m_buffer_head_timestamp; 294 pthread_mutex_unlock(&m_framecounter_lock); 295 } 296 297 /** 298 * \brief return the timestamp of the last frame in the buffer 299 * 300 * This function returns the timestamp of the last frame in 301 * the StreamProcessor's buffer. It also returns the framecounter 302 * value for which this timestamp is valid. 303 * 304 * @param ts address to store the timestamp in 305 * @param fc address to store the associated framecounter in 306 */ 307 void StreamProcessor::getBufferTailTimestamp(uint64_t *ts, uint64_t *fc) { 308 pthread_mutex_lock(&m_framecounter_lock); 309 *fc = m_framecounter; 310 *ts = m_buffer_tail_timestamp; 311 pthread_mutex_unlock(&m_framecounter_lock); 172 312 } 173 313 … … 177 317 */ 178 318 void StreamProcessor::resetFrameCounter() { 179 ZERO_ATOMIC((SInt32 *)&m_framecounter); 319 pthread_mutex_lock(&m_framecounter_lock); 320 m_framecounter = 0; 321 pthread_mutex_unlock(&m_framecounter_lock); 180 322 } 181 323 branches/streaming-rework/src/libstreaming/StreamProcessor.h
r383 r384 34 34 #include "PortManager.h" 35 35 #include "streamstatistics.h" 36 37 #include <pthread.h> 36 38 37 39 namespace FreebobStreaming { … … 73 75 74 76 bool xrunOccurred() { return (m_xruns>0);}; 75 76 /**77 * This is used for implementing the synchronisation.78 * As long as this function doesn't return true, the current buffer79 * contents are not transfered to the packet decoders.80 *81 * This means that there can be more events in the buffer than82 * one period worth of them, should the synchronisation mechanism83 * require this84 * @return85 */86 virtual bool isOnePeriodReady()=0;87 88 unsigned int getNbPeriodsReady() { if(m_period) return m_framecounter/m_period; else return 0;};89 virtual void decrementFrameCounter();90 virtual void incrementFrameCounter(int nbframes);91 77 92 78 // move to private? 93 void resetFrameCounter();94 79 void resetXrunCounter(); 95 80 … … 99 84 bool isEnabled() {return !m_disabled;}; 100 85 101 virtual bool transfer(); ///< transfer the buffer contents from/to client 86 virtual bool putFrames(unsigned int nbframes, int64_t ts); ///< transfer the buffer contents from client 87 virtual bool getFrames(unsigned int nbframes, int64_t ts); ///< transfer the buffer contents to the client 102 88 103 89 virtual bool reset(); ///< reset the streams & buffers (e.g. after xrun) … … 111 97 virtual void setVerboseLevel(int l); 112 98 113 virtual bool preparedForStop() {return true;}; 114 virtual bool preparedForStart() {return true;}; 99 virtual bool prepareForStop() {return true;}; 100 virtual bool prepareForStart() {return true;}; 101 102 virtual bool prepareForEnable() {return true;}; 103 virtual bool prepareForDisable() {return true;}; 115 104 116 105 protected: … … 124 113 125 114 unsigned int m_xruns; 126 signed int m_framecounter;127 115 128 116 unsigned int m_framerate; 129 117 130 118 StreamProcessorManager *m_manager; 131 119 132 120 bool m_running; 133 121 bool m_disabled; … … 141 129 DECLARE_DEBUG_MODULE; 142 130 131 // frame counter & sync stuff 132 public: 133 /** 134 * @brief Can this StreamProcessor handle a nframes of frames? 135 * 136 * this function indicates if the streamprocessor can handle nframes 137 * of frames. It is used to detect underruns-to-be. 138 * 139 * @param nframes number of frames 140 * @return true if the StreamProcessor can handle this amount of frames 141 * false if it can't 142 */ 143 virtual bool canClientTransferFrames(unsigned int nframes) {return true;}; 144 145 int getFrameCounter() {return m_framecounter;}; 146 147 void decrementFrameCounter(int nbframes, uint64_t new_timestamp); 148 void incrementFrameCounter(int nbframes, uint64_t new_timestamp); 149 void setFrameCounter(int new_framecounter, uint64_t new_timestamp); 150 void resetFrameCounter(); 151 152 void setBufferTailTimestamp(uint64_t new_timestamp); 153 void setBufferHeadTimestamp(uint64_t new_timestamp); 154 void setBufferTimestamps(uint64_t new_head, uint64_t new_tail); 155 /** 156 * \brief return the time until the next period boundary (in microseconds) 157 * 158 * Return the time until the next period boundary. If this StreamProcessor 159 * is the current synchronization source, this function is called to 160 * determine when a buffer transfer can be made. When this value is 161 * smaller than 0, a period boundary is assumed to be crossed, hence a 162 * transfer can be made. 163 * 164 * \return the time in usecs 165 */ 166 virtual int64_t getTimeUntilNextPeriodUsecs() = 0; 167 /** 168 * \brief return the time of the next period boundary (in microseconds) 169 * 170 * Returns the time of the next period boundary, in microseconds. The 171 * goal of this function is to determine the exact point of the period 172 * boundary. This is assumed to be the point at which the buffer transfer should 173 * take place, meaning that it can be used as a reference timestamp for transmitting 174 * StreamProcessors 175 * 176 * \return the time in usecs 177 */ 178 virtual uint64_t getTimeAtPeriodUsecs() = 0; 179 180 /** 181 * \brief return the time of the next period boundary (in internal units) 182 * 183 * The same as getTimeUntilNextPeriodUsecs() but in internal units. 184 * 185 * @return the time in internal units 186 */ 187 virtual uint64_t getTimeAtPeriod() = 0; 188 189 void getBufferHeadTimestamp(uint64_t *ts, uint64_t *fc); 190 void getBufferTailTimestamp(uint64_t *ts, uint64_t *fc); 191 192 bool setSyncSource(StreamProcessor *s); 193 float getTicksPerFrame() {return m_ticks_per_frame;}; 194 195 protected: 196 // the framecounter gives the number of frames in the buffer 197 signed int m_framecounter; 198 199 // the buffer tail timestamp gives the timestamp of the last frame 200 // that was put into the buffer 201 uint64_t m_buffer_tail_timestamp; 202 203 // the buffer head timestamp gives the timestamp of the first frame 204 // that was put into the buffer 205 uint64_t m_buffer_head_timestamp; 206 207 208 StreamProcessor *m_SyncSource; 209 210 float m_ticks_per_frame; 211 212 private: 213 // this mutex protects the access to the framecounter 214 // and the buffer head timestamp. 215 pthread_mutex_t m_framecounter_lock; 143 216 144 217 }; branches/streaming-rework/src/libstreaming/StreamProcessorManager.cpp
r383 r384 39 39 40 40 StreamProcessorManager::StreamProcessorManager(unsigned int period, unsigned int nb_buffers) 41 : m_nb_buffers(nb_buffers), m_period(period), m_xruns(0), m_isoManager(0), m_nbperiods(0) { 41 : m_SyncSource(NULL), m_nb_buffers(nb_buffers), m_period(period), m_xruns(0), 42 m_isoManager(0), m_nbperiods(0) { 42 43 43 44 } … … 146 147 } 147 148 149 bool StreamProcessorManager::setSyncSource(StreamProcessor *s) { 150 m_SyncSource=s; 151 return true; 152 } 153 154 StreamProcessor *StreamProcessorManager::getSyncSource() { 155 return m_SyncSource; 156 } 157 148 158 bool StreamProcessorManager::init() 149 159 { 150 160 debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); 151 161 152 // the tread that runs the packet iterators 162 // the tread that runs the StreamProcessor 163 // checking the period boundaries 153 164 m_streamingThread=new FreebobUtil::PosixThread(this, 154 165 m_thread_realtime, m_thread_priority+5, … … 169 180 m_isoManager->setVerboseLevel(getDebugLevel()); 170 181 171 // the tread that keeps the handler's cycle counters up to date 172 // NOTE: is lower priority nescessary? it can block 173 // m_isoManagerThread=new FreebobUtil::PosixThread(m_isoManager, m_thread_realtime, m_thread_priority+6, PTHREAD_CANCEL_DEFERRED); 174 175 // now that we are using a DLL, we don't need to run this at RT priority 176 // it only serves to cope with drift 177 // however, in order to make the DLL fast enough, we have to increase 178 // its bandwidth, making it more sensitive to deviations. These deviations 179 // are mostly determined by the time difference between reading the cycle 180 // time register and the local cpu clock. 181 182 // the tread that keeps the handler's cycle timers up to date 183 // and performs the actual packet transfer 184 // needs high priority 182 185 m_isoManagerThread=new FreebobUtil::PosixThread( 183 186 m_isoManager, … … 201 204 202 205 if(sem_init(&m_period_semaphore, 0, 0)) { 203 debugFatal( "Cannot init packettransfer semaphore\n");206 debugFatal( "Cannot init period transfer semaphore\n"); 204 207 debugFatal( " Error: %s\n",strerror(errno)); 205 208 return false; … … 212 215 213 216 debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing...\n"); 214 debugOutput( DEBUG_LEVEL_VERBOSE, " Receive processors...\n"); 217 218 // if no sync source is set, select one here 219 if(m_SyncSource == NULL) { 220 debugWarning("Sync Source is not set. Defaulting to first StreamProcessor.\n"); 221 } 222 215 223 for ( StreamProcessorVectorIterator it = m_ReceiveProcessors.begin(); 216 224 it != m_ReceiveProcessors.end(); 217 225 ++it ) { 226 if(m_SyncSource == NULL) { 227 debugWarning(" => Sync Source is %p.\n", *it); 228 m_SyncSource = *it; 229 } 230 } 231 232 for ( StreamProcessorVectorIterator it = m_TransmitProcessors.begin(); 233 it != m_TransmitProcessors.end(); 234 ++it ) { 235 if(m_SyncSource == NULL) { 236 debugWarning(" => Sync Source is %p.\n", *it); 237 m_SyncSource = *it; 238 } 239 } 240 241 // now do the actual preparation 242 debugOutput( DEBUG_LEVEL_VERBOSE, "Prepare Receive processors...\n"); 243 for ( StreamProcessorVectorIterator it = m_ReceiveProcessors.begin(); 244 it != m_ReceiveProcessors.end(); 245 ++it ) { 246 if(!(*it)->setSyncSource(m_SyncSource)) { 247 debugFatal( " could not set sync source (%p)...\n",(*it)); 248 return false; 249 } 250 218 251 if(!(*it)->prepare()) { 219 252 debugFatal( " could not prepare (%p)...\n",(*it)); 220 253 return false; 221 222 } 223 } 224 225 debugOutput( DEBUG_LEVEL_VERBOSE, " Transmit processors...\n"); 254 } 255 } 256 257 debugOutput( DEBUG_LEVEL_VERBOSE, "Prepare Transmit processors...\n"); 226 258 for ( StreamProcessorVectorIterator it = m_TransmitProcessors.begin(); 227 259 it != m_TransmitProcessors.end(); 228 260 ++it ) { 261 if(!(*it)->setSyncSource(m_SyncSource)) { 262 debugFatal( " could not set sync source (%p)...\n",(*it)); 263 return false; 264 } 229 265 if(!(*it)->prepare()) { 230 266 debugFatal( " could not prepare (%p)...\n",(*it)); 231 267 return false; 232 233 } 234 235 } 268 } 269 } 236 270 237 271 // if there are no stream processors registered, … … 245 279 } 246 280 281 // FIXME: this can be removed 247 282 bool StreamProcessorManager::Execute() 248 283 { 249 250 bool period_ready=true; 251 bool xrun_has_occured=false; 252 bool this_period_ready; 253 254 // debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "------------- EXECUTE -----------\n"); 255 256 if(!m_isoManager->iterate()) { 257 debugFatal("Could not iterate the isoManager\n"); 258 return false; 259 } 260 261 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, " RCV PROC: "); 262 for ( StreamProcessorVectorIterator it = m_ReceiveProcessors.begin(); 263 it != m_ReceiveProcessors.end(); 264 ++it ) { 265 266 this_period_ready = (*it)->isOnePeriodReady(); 267 period_ready = period_ready && this_period_ready; 268 // if (this_period_ready) { 269 // m_isoManager->disablePolling(*it); 270 // } 271 // 272 xrun_has_occured = xrun_has_occured || (*it)->xrunOccurred(); 273 debugOutputShort( DEBUG_LEVEL_VERY_VERBOSE, "(%d/%d/%d) ", period_ready, xrun_has_occured,(*it)->m_framecounter); 274 } 275 debugOutputShort( DEBUG_LEVEL_VERY_VERBOSE, "\n"); 276 277 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, " XMIT PROC: "); 278 for ( StreamProcessorVectorIterator it = m_TransmitProcessors.begin(); 279 it != m_TransmitProcessors.end(); 280 ++it ) { 281 this_period_ready = (*it)->isOnePeriodReady(); 282 period_ready = period_ready && this_period_ready; 283 // if (this_period_ready) { 284 // m_isoManager->disablePolling(*it); 285 // } 286 xrun_has_occured = xrun_has_occured || (*it)->xrunOccurred(); 287 debugOutputShort( DEBUG_LEVEL_VERY_VERBOSE, "(%d/%d/%d) ", period_ready, xrun_has_occured,(*it)->m_framecounter); 288 } 289 debugOutputShort( DEBUG_LEVEL_VERY_VERBOSE, "\n"); 290 291 if(xrun_has_occured) { 292 // do xrun signaling/handling 293 debugWarning("Streaming thread detected xrun\n"); 294 m_xruns++; 295 m_xrun_happened=true; 296 sem_post(&m_period_semaphore); 284 // temp measure, polling 285 usleep(1000); 286 287 // FIXME: move this to an IsoHandlerManager sub-thread 288 // and make this private again in IHM 289 m_isoManager->updateCycleTimers(); 297 290 298 return false; // stop thread 299 } 300 301 if(period_ready) { 302 // signal the waiting thread(s?) that a period is ready 303 sem_post(&m_period_semaphore); 304 debugOutputShort( DEBUG_LEVEL_VERY_VERBOSE, "Period done...\n"); 305 306 for ( StreamProcessorVectorIterator it = m_ReceiveProcessors.begin(); 307 it != m_ReceiveProcessors.end(); 308 ++it ) { 309 (*it)->decrementFrameCounter(); 310 // m_isoManager->enablePolling(*it); 311 312 } 313 314 for ( StreamProcessorVectorIterator it = m_TransmitProcessors.begin(); 315 it != m_TransmitProcessors.end(); 316 ++it ) { 317 (*it)->decrementFrameCounter(); 318 // m_isoManager->enablePolling(*it); 319 } 320 321 m_nbperiods++; 322 } 323 324 return true; 325 291 return true; 326 292 } 327 293 … … 335 301 it != m_ReceiveProcessors.end(); 336 302 ++it ) { 337 if (!(*it)->prepare dForStart()) {303 if (!(*it)->prepareForStart()) { 338 304 debugOutput(DEBUG_LEVEL_VERBOSE,"Receive stream processor (%p) failed to prepare for start\n", *it); 339 305 return false; … … 343 309 return false; 344 310 } 345 346 347 311 } 348 312 … … 351 315 it != m_TransmitProcessors.end(); 352 316 ++it ) { 353 if (!(*it)->prepare dForStart()) {317 if (!(*it)->prepareForStart()) { 354 318 debugOutput(DEBUG_LEVEL_VERBOSE,"Transmit stream processor (%p) failed to prepare for start\n", *it); 355 319 return false; … … 359 323 return false; 360 324 } 361 362 325 } 363 326 … … 368 331 } 369 332 370 debugOutput( DEBUG_LEVEL_VERBOSE, "Starting IsoHandler...\n"); 333 debugOutput( DEBUG_LEVEL_VERBOSE, "Disabling StreamProcessors...\n"); 334 if (!disableStreamProcessors()) { 335 debugFatal("Could not disable StreamProcessors...\n"); 336 return false; 337 } 338 339 debugOutput( DEBUG_LEVEL_VERBOSE, "Starting IsoHandlers...\n"); 371 340 if (!m_isoManager->startHandlers(0)) { 372 341 debugFatal("Could not start handlers...\n"); … … 374 343 } 375 344 376 debugOutput( DEBUG_LEVEL_VERBOSE, "Starting streaming thread...\n"); 377 345 debugOutput( DEBUG_LEVEL_VERBOSE, "Starting streaming threads...\n"); 346 347 // note: libraw1394 doesn't like it if you poll() and/or iterate() before 348 // starting the streams. 378 349 // start the runner thread 350 // FIXME: maybe this should go into the isomanager itself. 351 m_isoManagerThread->Start(); 352 353 // start the runner thread 354 // FIXME: not used anymore (for updatecycletimers ATM, but that's not good) 379 355 m_streamingThread->Start(); 380 381 // start the runner thread382 m_isoManagerThread->Start();383 356 384 357 debugOutput( DEBUG_LEVEL_VERBOSE, "Waiting for all StreamProcessors to start running...\n"); … … 434 407 435 408 // now we reset the frame counters 436 // FIXME: check how we are going to do sync437 409 for ( StreamProcessorVectorIterator it = m_ReceiveProcessors.begin(); 438 410 it != m_ReceiveProcessors.end(); … … 467 439 468 440 debugOutput( DEBUG_LEVEL_VERBOSE, "Enabling StreamProcessors...\n"); 469 // and we enable the streamprocessors470 for ( StreamProcessorVectorIterator it = m_ReceiveProcessors.begin();471 it != m_ReceiveProcessors.end(); 472 ++it ) {473 (*it)->enable();474 m_isoManager->enablePolling(*it);475 }476 477 for ( StreamProcessorVectorIterator it = m_TransmitProcessors.begin(); 478 it != m_TransmitProcessors.end();479 ++it) {480 (*it)->enable();481 m_isoManager->enablePolling(*it);441 442 debugOutput( DEBUG_LEVEL_VERBOSE, " Sync Source StreamProcessor...\n"); 443 if (!m_SyncSource->prepareForEnable()) { 444 debugFatal("Could not prepare Sync Source StreamProcessor for enable()...\n"); 445 return false; 446 } 447 448 m_SyncSource->enable(); 449 450 debugOutput( DEBUG_LEVEL_VERBOSE, " All StreamProcessors...\n"); 451 if (!enableStreamProcessors()) { 452 debugFatal("Could not enable StreamProcessors...\n"); 453 return false; 482 454 } 483 455 … … 509 481 it != m_ReceiveProcessors.end(); 510 482 ++it ) { 511 if(!(*it)->prepare dForStop()) allReady = false;483 if(!(*it)->prepareForStop()) allReady = false; 512 484 } 513 485 … … 515 487 it != m_TransmitProcessors.end(); 516 488 ++it ) { 517 if(!(*it)->prepare dForStop()) allReady = false;489 if(!(*it)->prepareForStop()) allReady = false; 518 490 } 519 491 usleep(1000); … … 560 532 } 561 533 562 bool StreamProcessorManager::waitForPeriod() { 563 564 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "enter...\n"); 565 566 // Wait for packetizer thread to signal a period completion 567 sem_wait(&m_period_semaphore); 568 569 if(m_xrun_happened) { 570 debugWarning("Detected underrun\n"); 571 dumpInfo(); 572 return false; 573 } 574 534 /** 535 * Enables the registered StreamProcessors 536 * @return true if successful, false otherwise 537 */ 538 bool StreamProcessorManager::enableStreamProcessors() { 539 // and we enable the streamprocessors 540 for ( StreamProcessorVectorIterator it = m_ReceiveProcessors.begin(); 541 it != m_ReceiveProcessors.end(); 542 ++it ) { 543 (*it)->prepareForEnable(); 544 (*it)->enable(); 545 } 546 547 for ( StreamProcessorVectorIterator it = m_TransmitProcessors.begin(); 548 it != m_TransmitProcessors.end(); 549 ++it ) { 550 (*it)->prepareForEnable(); 551 (*it)->enable(); 552 } 575 553 return true; 576 577 } 578 554 } 555 556 /** 557 * Disables the registered StreamProcessors 558 * @return true if successful, false otherwise 559 */ 560 bool StreamProcessorManager::disableStreamProcessors() { 561 // and we disable the streamprocessors 562 for ( StreamProcessorVectorIterator it = m_ReceiveProcessors.begin(); 563 it != m_ReceiveProcessors.end(); 564 ++it ) { 565 (*it)->prepareForDisable(); 566 (*it)->disable(); 567 } 568 569 for ( StreamProcessorVectorIterator it = m_TransmitProcessors.begin(); 570 it != m_TransmitProcessors.end(); 571 ++it ) { 572 (*it)->prepareForDisable(); 573 (*it)->disable(); 574 } 575 return true; 576 } 577 578 /** 579 * Called upon Xrun events. This brings all StreamProcessors back 580 * into their starting state, and then carries on streaming. This should 581 * have the same effect as restarting the whole thing. 582 * 583 * @return true if successful, false otherwise 584 */ 579 585 bool StreamProcessorManager::handleXrun() { 580 586 … … 583 589 /* 584 590 * Reset means: 585 * 1) Stopping the packetizer thread 591 * 1) Disabling the SP's, so that they don't process any packets 592 * note: the isomanager does keep on delivering/requesting them 586 593 * 2) Bringing all buffers & streamprocessors into a know state 587 594 * - Clear all capture buffers 588 595 * - Put nb_periods*period_size of null frames into the playback buffers 589 * 3) Re starting the packetizer thread596 * 3) Re-enable the SP's 590 597 */ 591 debugOutput( DEBUG_LEVEL_VERBOSE, " Stopping processormanager...\n");592 if(!stop()) {593 debugFatal("Could not stop.\n");598 debugOutput( DEBUG_LEVEL_VERBOSE, "Disabling StreamProcessors...\n"); 599 if (!disableStreamProcessors()) { 600 debugFatal("Could not disable StreamProcessors...\n"); 594 601 return false; 595 602 } … … 597 604 debugOutput( DEBUG_LEVEL_VERBOSE, "Resetting Processors...\n"); 598 605 599 // now we reset the frame counters606 // now we reset the streamprocessors 600 607 for ( StreamProcessorVectorIterator it = m_ReceiveProcessors.begin(); 601 608 it != m_ReceiveProcessors.end(); … … 611 618 (*it)->dumpInfo(); 612 619 } 613 614 620 } 615 621 … … 629 635 } 630 636 631 debugOutput( DEBUG_LEVEL_VERBOSE, "Starting processormanager...\n"); 632 633 if(!start()) { 634 debugFatal("Could not start.\n"); 635 return false; 636 } 637 637 debugOutput( DEBUG_LEVEL_VERBOSE, "Enabling StreamProcessors...\n"); 638 639 debugOutput( DEBUG_LEVEL_VERBOSE, " Sync Source StreamProcessor...\n"); 640 if (!m_SyncSource->prepareForEnable()) { 641 debugFatal("Could not prepare Sync Source StreamProcessor for enable()...\n"); 642 return false; 643 } 644 645 m_SyncSource->enable(); 646 647 debugOutput( DEBUG_LEVEL_VERBOSE, " All StreamProcessors...\n"); 648 if (!enableStreamProcessors()) { 649 debugFatal("Could not enable StreamProcessors...\n"); 650 return false; 651 } 638 652 639 653 debugOutput( DEBUG_LEVEL_VERBOSE, "Xrun handled...\n"); 640 654 641 642 655 return true; 643 656 } 644 657 658 /** 659 * @brief Waits until the next period of samples is ready 660 * 661 * This function does not return until a full period of samples is (or should be) 662 * ready to be transferred. 663 * 664 * @return true if the period is ready, false if an xrun occurred 665 */ 666 bool StreamProcessorManager::waitForPeriod() { 667 int time_till_next_period; 668 669 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "enter...\n"); 670 671 assert(m_SyncSource); 672 673 time_till_next_period=m_SyncSource->getTimeUntilNextPeriodUsecs(); 674 675 while(time_till_next_period > 0) { 676 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "waiting for %d usecs...\n", time_till_next_period); 677 678 // wait for the period 679 usleep(time_till_next_period); 680 681 // check if it is still true 682 time_till_next_period=m_SyncSource->getTimeUntilNextPeriodUsecs(); 683 } 684 685 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "delayed for %d usecs...\n", time_till_next_period); 686 687 // this is to notify the client of the delay 688 // that we introduced 689 m_delayed_usecs=time_till_next_period; 690 691 // we save the 'ideal' time of the transfer at this point, 692 // because we can have interleaved read - process - write 693 // cycles making that we modify a receiving stream's buffer 694 // before we get to writing. 695 // NOTE: before waitForPeriod() is called again, both the transmit 696 // and the receive processors should have done their transfer. 697 m_time_of_transfer=m_SyncSource->getTimeAtPeriod(); 698 debugOutput( DEBUG_LEVEL_VERBOSE, "transfer at %llu ticks...\n", 699 m_time_of_transfer); 700 701 // check if xruns occurred on the Iso side. 702 // also check if xruns will occur should we transfer() now 703 bool xrun_occurred=false; 704 705 for ( StreamProcessorVectorIterator it = m_ReceiveProcessors.begin(); 706 it != m_ReceiveProcessors.end(); 707 ++it ) { 708 // a xrun has occurred on the Iso side 709 xrun_occurred |= (*it)->xrunOccurred(); 710 711 // if this is true, a xrun will occur 712 xrun_occurred |= !((*it)->canClientTransferFrames(m_period)); 713 714 #ifdef DEBUG 715 if ((*it)->xrunOccurred()) { 716 debugWarning("Xrun on RECV SP %p due to ISO xrun\n",*it); 717 } 718 if (!((*it)->canClientTransferFrames(m_period))) { 719 debugWarning("Xrun on RECV SP %p due to buffer xrun\n",*it); 720 } 721 #endif 722 723 } 724 for ( StreamProcessorVectorIterator it = m_TransmitProcessors.begin(); 725 it != m_TransmitProcessors.end(); 726 ++it ) { 727 // a xrun has occurred on the Iso side 728 xrun_occurred |= (*it)->xrunOccurred(); 729 730 // if this is true, a xrun will occur 731 xrun_occurred |= !((*it)->canClientTransferFrames(m_period)); 732 733 #ifdef DEBUG 734 if ((*it)->xrunOccurred()) { 735 debugWarning("Xrun on XMIT SP %p due to ISO xrun\n",*it); 736 } 737 if (!((*it)->canClientTransferFrames(m_period))) { 738 debugWarning("Xrun on XMIT SP %p due to buffer xrun\n",*it); 739 } 740 #endif 741 } 742 743 // now we can signal the client that we are (should be) ready 744 return !xrun_occurred; 745 } 746 747 /** 748 * @brief Transfer one period of frames for both receive and transmit StreamProcessors 749 * 750 * Transfers one period of frames from the client side to the Iso side and vice versa. 751 * 752 * @return true if successful, false otherwise (indicates xrun). 753 */ 645 754 bool StreamProcessorManager::transfer() { 646 647 debugOutput( DEBUG_LEVEL_VERBOSE, "Transferring period...\n"); 648 649 // a static cast could make sure that there is no performance 650 // penalty for the virtual functions (to be checked) 651 652 for ( StreamProcessorVectorIterator it = m_ReceiveProcessors.begin(); 653 it != m_ReceiveProcessors.end(); 654 ++it ) { 655 if(!(*it)->transfer()) { 656 debugFatal("could not transfer() stream processor (%p)",*it); 657 return false; 658 } 659 } 660 661 for ( StreamProcessorVectorIterator it = m_TransmitProcessors.begin(); 662 it != m_TransmitProcessors.end(); 663 ++it ) { 664 if(!(*it)->transfer()) { 665 debugFatal("could not transfer() stream processor (%p)",*it); 666 return false; 667 } 668 } 669 670 return true; 671 } 755 756 debugOutput( DEBUG_LEVEL_VERBOSE, "Transferring period...\n"); 757 758 if (!transfer(StreamProcessor::E_Receive)) return false; 759 if (!transfer(StreamProcessor::E_Transmit)) return false; 760 761 return true; 762 } 763 764 /** 765 * @brief Transfer one period of frames for either the receive or transmit StreamProcessors 766 * 767 * Transfers one period of frames from the client side to the Iso side or vice versa. 768 * 769 * @param t The processor type to tranfer for (receive or transmit) 770 * @return true if successful, false otherwise (indicates xrun). 771 */ 672 772 673 773 bool StreamProcessorManager::transfer(enum StreamProcessor::EProcessorType t) { 674 675 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Transferring period...\n"); 676 677 // a static cast could make sure that there is no performance 678 // penalty for the virtual functions (to be checked) 679 if (t==StreamProcessor::E_Receive) { 680 for ( StreamProcessorVectorIterator it = m_ReceiveProcessors.begin(); 681 it != m_ReceiveProcessors.end(); 682 ++it ) { 683 if(!(*it)->transfer()) { 684 debugFatal("could not transfer() stream processor (%p)",*it); 685 return false; 686 } 687 } 688 } else { 689 for ( StreamProcessorVectorIterator it = m_TransmitProcessors.begin(); 690 it != m_TransmitProcessors.end(); 691 ++it ) { 692 if(!(*it)->transfer()) { 693 debugFatal("could not transfer() stream processor (%p)",*it); 694 return false; 695 } 696 } 697 } 698 699 return true; 774 int64_t time_of_transfer; 775 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Transferring period...\n"); 776 777 // first we should find out on what time this transfer is 778 // supposed to be happening. this time will become the time 779 // stamp for the transmitted buffer. 780 // NOTE: maybe we should include the transfer delay here, that 781 // would make it equal for all types of SP's 782 time_of_transfer=m_time_of_transfer; 783 784 // a static cast could make sure that there is no performance 785 // penalty for the virtual functions (to be checked) 786 if (t==StreamProcessor::E_Receive) { 787 for ( StreamProcessorVectorIterator it = m_ReceiveProcessors.begin(); 788 it != m_ReceiveProcessors.end(); 789 ++it ) { 790 uint64_t buffer_tail_ts; 791 uint64_t fc; 792 int64_t ts; 793 794 (*it)->getBufferTailTimestamp(&buffer_tail_ts,&fc); 795 ts = buffer_tail_ts; 796 ts += (int64_t)((-(int64_t)fc) * m_SyncSource->getTicksPerFrame()); 797 // NOTE: ts can be negative due to wraparound, it is the responsability of the 798 // SP to deal with that. 799 800 float tmp=m_SyncSource->getTicksPerFrame(); 801 802 debugOutput(DEBUG_LEVEL_VERBOSE, "=> TS=%11lld, BLT=%11llu, FC=%5d, TPF=%f\n", 803 ts, buffer_tail_ts, fc, tmp 804 ); 805 debugOutput(DEBUG_LEVEL_VERBOSE, " TPF=%f\n", tmp); 806 807 #ifdef DEBUG 808 { 809 uint64_t ts_tail=0; 810 uint64_t fc_tail=0; 811 812 uint64_t ts_head=0; 813 uint64_t fc_head=0; 814 815 int cnt=0; 816 817 (*it)->getBufferHeadTimestamp(&ts_head,&fc_head); 818 (*it)->getBufferTailTimestamp(&ts_tail,&fc_tail); 819 820 while((fc_head != fc_tail) && (cnt++ < 10)) { 821 (*it)->getBufferHeadTimestamp(&ts_head,&fc_head); 822 (*it)->getBufferTailTimestamp(&ts_tail,&fc_tail); 823 } 824 825 debugOutput(DEBUG_LEVEL_VERBOSE,"R * HEAD: TS=%llu, FC=%llu | TAIL: TS=%llu, FC=%llu, %d\n", 826 ts_tail, fc_tail, ts_head, fc_head, cnt); 827 } 828 #endif 829 830 if(!(*it)->getFrames(m_period, ts)) { 831 debugOutput(DEBUG_LEVEL_VERBOSE,"could not getFrames(%u) from stream processor (%p)", 832 m_period,*it); 833 return false; // buffer underrun 834 } 835 836 #ifdef DEBUG 837 { 838 uint64_t ts_tail=0; 839 uint64_t fc_tail=0; 840 841 uint64_t ts_head=0; 842 uint64_t fc_head=0; 843 844 int cnt=0; 845 846 (*it)->getBufferHeadTimestamp(&ts_head,&fc_head); 847 (*it)->getBufferTailTimestamp(&ts_tail,&fc_tail); 848 849 while((fc_head != fc_tail) && (cnt++ < 10)) { 850 (*it)->getBufferHeadTimestamp(&ts_head,&fc_head); 851 (*it)->getBufferTailTimestamp(&ts_tail,&fc_tail); 852 } 853 854 debugOutput(DEBUG_LEVEL_VERBOSE,"R > HEAD: TS=%llu, FC=%llu | TAIL: TS=%llu, FC=%llu, %d\n", 855 ts_tail, fc_tail, ts_head, fc_head, cnt); 856 } 857 #endif 858 859 } 860 } else { 861 for ( StreamProcessorVectorIterator it = m_TransmitProcessors.begin(); 862 it != m_TransmitProcessors.end(); 863 ++it ) { 864 865 #ifdef DEBUG 866 { 867 uint64_t ts_tail=0; 868 uint64_t fc_tail=0; 869 870 uint64_t ts_head=0; 871 uint64_t fc_head=0; 872 873 int cnt=0; 874 875 (*it)->getBufferHeadTimestamp(&ts_head,&fc_head); 876 (*it)->getBufferTailTimestamp(&ts_tail,&fc_tail); 877 878 while((fc_head != fc_tail) && (cnt++ < 10)) { 879 (*it)->getBufferHeadTimestamp(&ts_head,&fc_head); 880 (*it)->getBufferTailTimestamp(&ts_tail,&fc_tail); 881 } 882 883 debugOutput(DEBUG_LEVEL_VERBOSE,"T * HEAD: TS=%llu, FC=%llu | TAIL: TS=%llu, FC=%llu, %d\n", 884 ts_tail, fc_tail, ts_head, fc_head, cnt); 885 } 886 #endif 887 888 if(!(*it)->putFrames(m_period,time_of_transfer)) { 889 debugOutput(DEBUG_LEVEL_VERBOSE, "could not putFrames(%u,%llu) to stream processor (%p)", 890 m_period, time_of_transfer, *it); 891 return false; // buffer overrun 892 } 893 894 #ifdef DEBUG 895 { 896 uint64_t ts_tail=0; 897 uint64_t fc_tail=0; 898 899 uint64_t ts_head=0; 900 uint64_t fc_head=0; 901 902 int cnt=0; 903 904 (*it)->getBufferHeadTimestamp(&ts_head,&fc_head); 905 (*it)->getBufferTailTimestamp(&ts_tail,&fc_tail); 906 907 while((fc_head != fc_tail) && (cnt++ < 10)) { 908 (*it)->getBufferHeadTimestamp(&ts_head,&fc_head); 909 (*it)->getBufferTailTimestamp(&ts_tail,&fc_tail); 910 } 911 912 debugOutput(DEBUG_LEVEL_VERBOSE,"T > HEAD: TS=%llu, FC=%llu | TAIL: TS=%llu, FC=%llu, %d\n", 913 ts_tail, fc_tail, ts_head, fc_head, cnt); 914 } 915 #endif 916 } 917 } 918 919 return true; 700 920 } 701 921 branches/streaming-rework/src/libstreaming/StreamProcessorManager.h
r383 r384 54 54 public FreebobUtil::RunnableInterface { 55 55 56 friend class StreamRunner;57 58 56 public: 59 57 … … 64 62 bool prepare(); ///< to be called after the processors are registered 65 63 66 virtual void setVerboseLevel(int l); 67 void dumpInfo(); 64 bool start(); 65 bool stop(); 66 68 67 69 68 // this is the setup API 70 69 bool registerProcessor(StreamProcessor *processor); ///< start managing a streamprocessor 71 70 bool unregisterProcessor(StreamProcessor *processor); ///< stop managing a streamprocessor 71 72 bool enableStreamProcessors(); /// enable registered StreamProcessors 73 bool disableStreamProcessors(); /// disable registered StreamProcessors 72 74 73 75 void setPeriodSize(unsigned int period); … … 83 85 84 86 // the client-side functions 85 bool xrunOccurred();86 int getXrunCount() {return m_xruns;};87 87 88 88 bool waitForPeriod(); ///< wait for the next period … … 90 90 bool transfer(); ///< transfer the buffer contents from/to client 91 91 bool transfer(enum StreamProcessor::EProcessorType); ///< transfer the buffer contents from/to client (single processor type) 92 92 93 int getDelayedUsecs() {return m_delayed_usecs;}; 94 bool xrunOccurred(); 95 int getXrunCount() {return m_xruns;}; 96 97 private: 98 int m_delayed_usecs; 99 // this stores the time at which the next transfer should occur 100 // usually this is in the past, but it is needed as a timestamp 101 // for the transmit SP's 102 uint64_t m_time_of_transfer; 103 104 public: 93 105 bool handleXrun(); ///< reset the streams & buffers after xrun 94 95 bool start();96 bool stop();97 106 98 107 bool setThreadParameters(bool rt, int priority); 99 108 100 // the ISO-side functions 109 virtual void setVerboseLevel(int l); 110 void dumpInfo(); 111 112 113 // the sync source stuff 114 private: 115 StreamProcessor *m_SyncSource; 116 117 public: 118 bool setSyncSource(StreamProcessor *s); 119 StreamProcessor * getSyncSource(); 120 121 101 122 protected: 102 123 int signalWaiters(); // call this to signal a period boundary … … 116 137 StreamProcessorVector m_ReceiveProcessors; 117 138 StreamProcessorVector m_TransmitProcessors; 139 140 118 141 119 142 unsigned int m_nb_buffers; branches/streaming-rework/src/libutil/cycles.h
r360 r384 32 32 33 33 /* 34 * Standard way to access the cycle counter on i586+ CPUs.34 * Standard way to access the cycle timer on i586+ CPUs. 35 35 * Currently only used on SMP. 36 36 * branches/streaming-rework/src/libutil/SystemTimeSource.cpp
r360 r384 35 35 36 36 SystemTimeSource::SystemTimeSource() { 37 InitTime();37 // InitTime(); 38 38 } 39 39 … … 43 43 44 44 freebob_microsecs_t SystemTimeSource::getCurrentTime() { 45 return GetMicroSeconds(); 45 struct timeval tv; 46 gettimeofday(&tv, NULL); 47 return tv.tv_sec * 1000000ULL + tv.tv_usec; 48 49 // return GetMicroSeconds(); 46 50 } 47 51 branches/streaming-rework/src/libutil/SystemTimeSource.h
r360 r384 46 46 freebob_microsecs_t getCurrentTime(); 47 47 freebob_microsecs_t getCurrentTimeAsUsecs(); 48 inline freebob_microsecs_t unWrapTime(freebob_microsecs_t t) {return t;}; 49 inline freebob_microsecs_t wrapTime(freebob_microsecs_t t) {return t;}; 48 50 49 51 protected: branches/streaming-rework/src/libutil/Time.h
r360 r384 72 72 struct timespec ts; 73 73 clock_gettime(CLOCK_MONOTONIC, &ts); 74 return (freebob_microsecs_t)ts.tv_sec * 1000000 + ts.tv_nsec / 1000;74 return (freebob_microsecs_t)ts.tv_sec * 1000000LL + ts.tv_nsec / 1000; 75 75 } 76 76 #endif branches/streaming-rework/src/libutil/TimeSource.cpp
r360 r384 30 30 #include "TimeSource.h" 31 31 32 #include <time.h> 33 34 #include <assert.h> 35 32 36 #include "libutil/Time.h" 33 37 34 38 namespace FreebobUtil { 35 39 36 TimeSource::TimeSource() { 40 IMPL_DEBUG_MODULE( TimeSource, TimeSource, DEBUG_LEVEL_NORMAL ); 41 42 TimeSource::TimeSource() : 43 m_Master(NULL), m_last_master_time(0), m_last_time(0), 44 m_slave_rate(0.0), m_slave_offset(0), m_last_err(0.0) 45 { 37 46 38 47 } … … 41 50 42 51 } 52 /** 53 * (re)Initializes the TimeSource 54 * 55 * @return true if successful 56 */ 57 void TimeSource::initSlaveTimeSource() { 58 freebob_microsecs_t my_time; 59 freebob_microsecs_t master_time; 60 freebob_microsecs_t my_time2; 61 freebob_microsecs_t master_time2; 62 63 if (m_Master) { 64 my_time=getCurrentTime(); 65 master_time=m_Master->getCurrentTime(); 66 67 struct timespec ts; 68 69 // sleep for ten milliseconds 70 ts.tv_sec=0; 71 ts.tv_nsec=10000000L; 72 73 nanosleep(&ts,NULL); 74 75 my_time2=getCurrentTime(); 76 master_time2=m_Master->getCurrentTime(); 77 78 float diff_slave=my_time2-my_time; 79 float diff_master=master_time2-master_time; 80 81 m_slave_rate=diff_slave/diff_master; 82 83 // average of the two offset estimates 84 m_slave_offset = my_time-wrapTime((freebob_microsecs_t)(master_time*m_slave_rate)); 85 m_slave_offset += my_time2-wrapTime((freebob_microsecs_t)(master_time2*m_slave_rate)); 86 m_slave_offset /= 2; 87 88 m_last_master_time=master_time2; 89 m_last_time=my_time2; 90 91 debugOutput(DEBUG_LEVEL_NORMAL,"init slave: master=%lu, master2=%lu, diff=%f\n", 92 master_time, master_time2, diff_master); 93 debugOutput(DEBUG_LEVEL_NORMAL,"init slave: slave =%lu, slave2 =%lu, diff=%f\n", 94 my_time, my_time2, diff_slave); 95 debugOutput(DEBUG_LEVEL_NORMAL,"init slave: slave rate=%f, slave_offset=%lu\n", 96 m_slave_rate, m_slave_offset 97 ); 98 } 99 100 101 } 102 103 /** 104 * Maps a time point of the master to a time point 105 * on it's own timeline 106 * 107 * @return the mapped time point 108 */ 109 freebob_microsecs_t TimeSource::mapMasterTime(freebob_microsecs_t master_time) { 110 if(m_Master) { 111 // calculate the slave based upon the master 112 // and the estimated rate 113 114 // linear interpolation 115 int delta_master=master_time-m_last_master_time; 116 117 float offset=m_slave_rate * ((float)delta_master); 118 119 freebob_microsecs_t mapped=m_last_time+(int)offset; 120 121 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"map time: master=%d, offset=%f, slave_base=%lu, pred_ticks=%lu\n", 122 master_time, offset, m_last_time,mapped 123 ); 124 125 return wrapTime(mapped); 126 127 } else { 128 debugOutput( DEBUG_LEVEL_VERBOSE, "Requested map for non-slave TimeSource\n"); 129 130 return master_time; 131 } 132 } 133 134 /** 135 * Update the internal state of the TimeSource 136 * 137 */ 138 bool TimeSource::updateTimeSource() { 139 // update all slaves 140 for ( TimeSourceVectorIterator it = m_Slaves.begin(); 141 it != m_Slaves.end(); ++it ) { 142 143 // update the slave with the current 144 // master time 145 if (!(*it)->updateTimeSource()) return false; 146 } 147 148 // this TimeSource has a master 149 if(m_Master) { 150 freebob_microsecs_t my_time=getCurrentTime(); 151 freebob_microsecs_t master_time=m_Master->getCurrentTime(); 152 153 // we assume that the master and slave time are 154 // measured at the same time, but that of course is 155 // not really true. The DLL will have to filter this 156 // out. 157 158 // the difference in master time 159 int64_t delta_master; 160 if (master_time > m_last_master_time) { 161 delta_master=master_time-m_last_master_time; 162 } else { // wraparound 163 delta_master=m_Master->unWrapTime(master_time)-m_last_master_time; 164 } 165 166 // the difference in slave time 167 int64_t delta_slave; 168 if (my_time > m_last_time) { 169 delta_slave=my_time-m_last_time; 170 } else { // wraparound 171 delta_slave=unWrapTime(my_time)-m_last_time; 172 } 173 174 // the estimated slave difference 175 int delta_slave_est=(int)(m_slave_rate * ((double)delta_master)); 176 177 // the measured & estimated rate 178 double rate_meas=((double)delta_slave/(double)delta_master); 179 double rate_est=((double)m_slave_rate); 180 181 m_last_err=(rate_meas-rate_est); 182 183 m_slave_rate += 0.01*m_last_err; 184 185 debugOutput(DEBUG_LEVEL_VERBOSE,"update slave: master=%llu, master2=%llu, diff=%lld\n", 186 master_time, m_last_master_time, delta_master); 187 debugOutput(DEBUG_LEVEL_VERBOSE,"update slave: slave =%llu, slave2 =%llu, diff=%lld, diff_est=%d\n", 188 my_time, m_last_time, delta_slave, delta_slave_est); 189 debugOutput(DEBUG_LEVEL_VERBOSE,"update slave: slave rate meas=%f, slave rate est=%f, err=%f, slave rate=%f\n", 190 rate_meas, rate_est, m_last_err, m_slave_rate 191 ); 192 193 194 m_last_master_time=master_time; 195 196 int64_t tmp = delta_slave_est; 197 tmp += m_last_time; 198 199 m_last_time = tmp; 200 201 202 203 } 204 205 return true; 206 } 207 208 /** 209 * Sets the master TimeSource for this timesource. 210 * This TimeSource will sync to the master TimeSource, 211 * making that it will be able to map a time point of 212 * the master to a time point on it's own timeline 213 * 214 * @param ts master TimeSource 215 * @return true if successful 216 */ 217 bool TimeSource::setMaster(TimeSource *ts) { 218 if (m_Master==NULL) { 219 m_Master=ts; 220 221 // initialize ourselves. 222 initSlaveTimeSource(); 223 224 return true; 225 } else return false; 226 } 227 228 /** 229 * Clears the master TimeSource for this timesource. 230 * 231 * @return true if successful 232 */ 233 void TimeSource::clearMaster() { 234 m_Master=NULL; 235 } 236 237 /** 238 * Registers a slave timesource to this master. 239 * A slave TimeSource will sync to this TimeSource, 240 * making that it will be able to map a time point of 241 * the master (this) TimeSource to a time point on 242 * it's own timeline 243 * 244 * @param ts slave TimeSource to register 245 * @return true if successful 246 */ 247 bool TimeSource::registerSlave(TimeSource *ts) { 248 // TODO: we should check for circular master-slave relationships. 249 250 debugOutput( DEBUG_LEVEL_VERBOSE, "Registering slave (%p)\n", ts); 251 assert(ts); 252 253 // inherit debug level 254 ts->setVerboseLevel(getDebugLevel()); 255 256 if(ts->setMaster(this)) { 257 m_Slaves.push_back(ts); 258 return true; 259 } else { 260 return false; 261 } 262 } 263 264 /** 265 * Unregisters a slave TimeSource 266 * 267 * @param ts slave TimeSource to unregister 268 * @return true if successful 269 */ 270 bool TimeSource::unregisterSlave(TimeSource *ts) { 271 debugOutput( DEBUG_LEVEL_VERBOSE, "Unregistering TimeSource (%p)\n", ts); 272 assert(ts); 273 274 for ( TimeSourceVectorIterator it = m_Slaves.begin(); 275 it != m_Slaves.end(); ++it ) { 276 277 if ( *it == ts ) { 278 m_Slaves.erase(it); 279 ts->clearMaster(); 280 return true; 281 } 282 } 283 284 debugOutput( DEBUG_LEVEL_VERBOSE, " TimeSource (%p) not found\n", ts); 285 286 return false; 287 } 288 289 /** 290 * Set verbosity level. 291 * All slave timesources get the same verbosity level 292 * 293 * @param l verbosity level 294 */ 295 void TimeSource::setVerboseLevel(int l) { 296 setDebugLevel(l); 297 298 for ( TimeSourceVectorIterator it = m_Slaves.begin(); 299 it != m_Slaves.end(); ++it ) { 300 301 (*it)->setVerboseLevel(l); 302 } 303 304 } 305 306 void TimeSource::printTimeSourceInfo() { 307 debugOutputShort( DEBUG_LEVEL_NORMAL, "TimeSource (%p) info\n", this); 308 debugOutputShort( DEBUG_LEVEL_NORMAL, " Master : %p\n", m_Master); 309 debugOutputShort( DEBUG_LEVEL_NORMAL, " Slave rate : %f\n", m_slave_rate); 310 debugOutputShort( DEBUG_LEVEL_NORMAL, " Slave offset : %lld\n", m_slave_offset); 311 debugOutputShort( DEBUG_LEVEL_NORMAL, " Last error : %f\n", m_last_err); 312 debugOutputShort( DEBUG_LEVEL_NORMAL, " Last master time : %llu\n",m_last_master_time ); 313 debugOutputShort( DEBUG_LEVEL_NORMAL, " Last slave time : %llu\n",m_last_time ); 314 315 316 for ( TimeSourceVectorIterator it = m_Slaves.begin(); 317 it != m_Slaves.end(); ++it ) { 318 319 (*it)->printTimeSourceInfo(); 320 } 321 } 43 322 44 323 } // end of namespace FreebobUtil branches/streaming-rework/src/libutil/TimeSource.h
r383 r384 31 31 #include "../debugmodule/debugmodule.h" 32 32 33 #include <vector> 34 33 35 typedef uint64_t freebob_microsecs_t; 34 36 35 37 namespace FreebobUtil { 36 38 39 class TimeSource; 40 typedef std::vector<TimeSource *> TimeSourceVector; 41 typedef std::vector<TimeSource *>::iterator TimeSourceVectorIterator; 42 43 /*! 44 \brief The base class for all TimeSource's. 45 46 Any object that can act as a source of timing 47 information should subclass this class and implement 48 its virtual functions. 49 50 A TimeSource can be slaved to another TimeSource, allowing 51 the mapping of the master's time to the slave's time. 52 */ 37 53 class TimeSource { 38 54 … … 44 60 virtual freebob_microsecs_t getCurrentTime()=0; 45 61 virtual freebob_microsecs_t getCurrentTimeAsUsecs()=0; 62 virtual freebob_microsecs_t unWrapTime(freebob_microsecs_t t)=0; 63 virtual freebob_microsecs_t wrapTime(freebob_microsecs_t t)=0; 64 65 freebob_microsecs_t mapMasterTime(freebob_microsecs_t t); 66 67 bool updateTimeSource(); 68 69 bool registerSlave(TimeSource *ts); 70 bool unregisterSlave(TimeSource *ts); 71 72 virtual void setVerboseLevel(int l); 73 74 virtual void printTimeSourceInfo(); 46 75 47 76 protected: 77 78 private: 79 bool setMaster(TimeSource *ts); 80 void clearMaster(); 81 82 void initSlaveTimeSource(); 83 84 TimeSource * m_Master; 85 TimeSourceVector m_Slaves; 86 87 freebob_microsecs_t m_last_master_time; 88 freebob_microsecs_t m_last_time; 89 90 double m_slave_rate; 91 int64_t m_slave_offset; 92 double m_last_err; 93 94 DECLARE_DEBUG_MODULE; 48 95 49 96 }; branches/streaming-rework/src/Makefile.am
r383 r384 27 27 libfreebob_la_LIBADD = -lrt 28 28 29 noinst_HEADERS = \ 30 configrom.h \ 31 csr1212.h \ 32 devicemanager.h \ 33 fbtypes.h \ 34 bounce/bounce_avdevice.h \ 35 motu/motu_avdevice.h \ 36 rme/rme_avdevice.h 29 noinst_HEADERS = configrom.h csr1212.h debugmodule/debugmodule.h \ 30 devicemanager.h fbtypes.h iavdevice.h threads.h bebob/bebob_avdevice.h \ 31 bebob/bebob_avdevice_subunit.h bebob/bebob_avplug.h bebob/bebob_dl_bcd.h bebob/bebob_dl_codes.h \ 32 bebob/bebob_dl_mgr.h bebob/bebob_functionblock.h bounce/bounce_avdevice.h \ 33 maudio/maudio_avdevice.h motu/motu_avdevice.h rme/rme_avdevice.h libfreebobavc/avc_connect.h \ 34 libfreebobavc/avc_definitions.h libfreebobavc/avc_extended_cmd_generic.h \ 35 libfreebobavc/avc_extended_plug_info.h libfreebobavc/avc_extended_stream_format.h \ 36 libfreebobavc/avc_extended_subunit_info.h libfreebobavc/avc_function_block.h libfreebobavc/avc_generic.h \ 37 libfreebobavc/avc_plug_info.h libfreebobavc/avc_serialize.h libfreebobavc/avc_signal_source.h \ 38 libfreebobavc/avc_subunit_info.h libfreebobavc/avc_unit_info.h libfreebobavc/ieee1394service.h \ 39 libstreaming/AmdtpPort.h libstreaming/AmdtpPortInfo.h libstreaming/AmdtpStreamProcessor.h \ 40 libstreaming/cip.h libstreaming/cycletimer.h libstreaming/IsoHandler.h \ 41 libstreaming/IsoHandlerManager.h libstreaming/IsoStream.h libstreaming/MotuPort.h \ 42 libstreaming/MotuPortInfo.h libstreaming/MotuStreamProcessor.h libstreaming/PacketBuffer.h \ 43 libstreaming/Port.h libstreaming/PortManager.h libstreaming/ringbuffer.h \ 44 libstreaming/StreamProcessor.h libstreaming/StreamProcessorManager.h libstreaming/streamstatistics.h \ 45 libutil/Atomic.h libutil/cycles.h libutil/DelayLockedLoop.h libutil/PosixThread.h \ 46 libutil/serialize.h libutil/SystemTimeSource.h libutil/Thread.h libutil/Time.h \ 47 libutil/TimeSource.h 37 48 38 49 libfreebob_la_SOURCES = \ 39 iavdevice.h \40 50 configrom.cpp \ 41 51 csr1212.c \ … … 43 53 freebob.cpp \ 44 54 xmlparser.c \ 45 threads.h \46 bebob/bebob_avdevice.h \47 55 bebob/bebob_avdevice.cpp \ 48 bebob/bebob_avdevice_xml.cpp \49 bebob/bebob_avdevice_subunit.h \50 56 bebob/bebob_avdevice_subunit.cpp \ 51 bebob/bebob_avplug.h\57 bebob/bebob_avdevice_xml.cpp \ 52 58 bebob/bebob_avplug.cpp \ 53 59 bebob/bebob_avplug_xml.cpp \ 54 bebob/bebob_functionblock.h \55 bebob/bebob_functionblock.cpp \56 bebob/bebob_dl_mgr.h \57 bebob/bebob_dl_mgr.cpp \58 bebob/bebob_dl_codes.h \59 bebob/bebob_dl_codes.cpp \60 bebob/bebob_dl_bcd.h \61 60 bebob/bebob_dl_bcd.cpp \ 62 motu/motu_avdevice.cpp \ 63 motu/motu_avdevice.h \ 64 rme/rme_avdevice.cpp \ 65 rme/rme_avdevice.h \ 66 bounce/bounce_avdevice.h \ 61 bebob/bebob_dl_codes.cpp \ 62 bebob/bebob_dl_mgr.cpp \ 63 bebob/bebob_functionblock.cpp \ 67 64 bounce/bounce_avdevice.cpp \ 68 maudio/maudio_avdevice.h \69 65 maudio/maudio_avdevice.cpp \ 66 motu/motu_avdevice.cpp \ 67 rme/rme_avdevice.cpp \ 68 debugmodule/debugmodule.cpp \ 70 69 libfreebobavc/avc_connect.cpp \ 71 70 libfreebobavc/avc_definitions.cpp \ … … 75 74 libfreebobavc/avc_extended_subunit_info.cpp \ 76 75 libfreebobavc/avc_function_block.cpp \ 77 libfreebobavc/avc_function_block.h \78 76 libfreebobavc/avc_generic.cpp \ 79 77 libfreebobavc/avc_plug_info.cpp \ 78 libfreebobavc/avc_serialize.cpp \ 80 79 libfreebobavc/avc_signal_source.cpp \ 81 80 libfreebobavc/avc_subunit_info.cpp \ 82 81 libfreebobavc/avc_unit_info.cpp \ 83 82 libfreebobavc/ieee1394service.cpp \ 84 libfreebobavc/avc_serialize.cpp \ 85 libfreebobavc/avc_connect.h \ 86 libfreebobavc/avc_definitions.h \ 87 libfreebobavc/avc_extended_cmd_generic.h \ 88 libfreebobavc/avc_extended_plug_info.h \ 89 libfreebobavc/avc_extended_stream_format.h \ 90 libfreebobavc/avc_extended_subunit_info.h \ 91 libfreebobavc/avc_generic.h \ 92 libfreebobavc/avc_plug_info.h \ 93 libfreebobavc/avc_signal_source.h \ 94 libfreebobavc/avc_subunit_info.h \ 95 libfreebobavc/avc_unit_info.h \ 96 libfreebobavc/ieee1394service.h \ 97 libfreebobavc/avc_serialize.h \ 98 debugmodule/debugmodule.h \ 99 debugmodule/debugmodule.cpp \ 83 libstreaming/AmdtpPort.cpp \ 84 libstreaming/AmdtpPortInfo.cpp \ 85 libstreaming/AmdtpStreamProcessor.cpp \ 100 86 libstreaming/cip.c \ 101 libstreaming/cyclecounter.h \102 87 libstreaming/freebob_streaming.cpp \ 103 88 libstreaming/IsoHandler.cpp \ 104 89 libstreaming/IsoHandlerManager.cpp \ 105 90 libstreaming/IsoStream.cpp \ 91 libstreaming/MotuPort.cpp \ 92 libstreaming/MotuPortInfo.cpp \ 93 libstreaming/MotuStreamProcessor.cpp \ 106 94 libstreaming/PacketBuffer.cpp \ 107 libstreaming/PortManager.cpp \108 95 libstreaming/Port.cpp \ 96 libstreaming/PortManager.cpp \ 97 libstreaming/ringbuffer.c \ 109 98 libstreaming/StreamProcessor.cpp \ 110 99 libstreaming/StreamProcessorManager.cpp \ 111 libstreaming/AmdtpPortInfo.cpp \112 libstreaming/AmdtpPort.cpp \113 libstreaming/AmdtpStreamProcessor.cpp \114 libstreaming/ringbuffer.c \115 100 libstreaming/streamstatistics.cpp \ 116 libstreaming/MotuStreamProcessor.cpp \117 libstreaming/MotuPort.cpp \118 libstreaming/MotuPortInfo.cpp \119 libutil/DelayLockedLoop.h \120 libutil/Atomic.h \121 libutil/PosixThread.h \122 libutil/Thread.h \123 101 libutil/DelayLockedLoop.cpp \ 124 102 libutil/PosixThread.cpp \ 125 libutil/Time.c \ 126 libutil/Time.h \ 127 libutil/TimeSource.cpp \ 128 libutil/TimeSource.h \ 103 libutil/serialize.cpp \ 129 104 libutil/SystemTimeSource.cpp \ 130 libutil/SystemTimeSource.h \ 131 libutil/cycles.h \ 132 libutil/serialize.h \ 133 libutil/serialize.cpp 134 105 libutil/Time.c \ 106 libutil/TimeSource.cpp 135 107 136 108 libfreebob_la_LDFLAGS = \ branches/streaming-rework/src/motu/motu_avdevice.cpp
r374 r384 19 19 * MA 02111-1307 USA. 20 20 */ 21 22 #ifdef ENABLE_MOTU 21 23 22 24 #include "motu/motu_avdevice.h" … … 937 939 938 940 } 941 #endif // ENABLE_MOTU branches/streaming-rework/src/motu/motu_avdevice.h
r336 r384 19 19 * MA 02111-1307 USA. 20 20 */ 21 22 #ifdef ENABLE_MOTU 21 23 22 24 #ifndef MOTUDEVICE_H … … 161 163 162 164 #endif 165 166 #endif // ENABLE_MOTU branches/streaming-rework/tests/Makefile.am
r360 r384 22 22 23 23 noinst_PROGRAMS = test-freebob test-extplugcmd test-fw410 freebob-server \ 24 test-volume test-mixer test-cycle counter test-sytmonitor24 test-volume test-mixer test-cycletimer test-sytmonitor 25 25 26 26 noinst_HEADERS = … … 53 53 TEST = test-freebob 54 54 55 test_cycle counter_LDADD = $(top_builddir)/src/libfreebob.la $(LIBIEC61883_LIBS) \55 test_cycletimer_LDADD = $(top_builddir)/src/libfreebob.la $(LIBIEC61883_LIBS) \ 56 56 $(LIBRAW1394_LIBS) $(LIBAVC1394_LIBS) 57 test_cycle counter_SOURCES = test-cyclecounter.cpp57 test_cycletimer_SOURCES = test-cycletimer.cpp 58 58 59 59 test_sytmonitor_LDADD = $(top_builddir)/src/libfreebob.la $(LIBIEC61883_LIBS) \ branches/streaming-rework/tests/SytMonitor.cpp
r360 r384 64 64 m_port,channel, 65 65 cycle,syt_timestamp, 66 CYCLE_ COUNTER_GET_SECS(syt_timestamp),67 CYCLE_ COUNTER_GET_CYCLES(syt_timestamp),68 CYCLE_ COUNTER_GET_OFFSET(syt_timestamp)66 CYCLE_TIMER_GET_SECS(syt_timestamp), 67 CYCLE_TIMER_GET_CYCLES(syt_timestamp), 68 CYCLE_TIMER_GET_OFFSET(syt_timestamp) 69 69 70 70 ); 71 71 72 72 // reconstruct the full cycle 73 unsigned int cc _ticks=m_handler->getCycleCounter();74 unsigned int cc_ cycles=TICKS_TO_CYCLES(cc_ticks);73 unsigned int cc=m_handler->getCycleTimer(); 74 unsigned int cc_ticks=CYCLE_TIMER_TO_TICKS(cc); 75 75 76 unsigned int cc_ seconds=TICKS_TO_SECS(cc_ticks);76 unsigned int cc_cycles=CYCLE_TIMER_GET_CYCLES(cc); 77 77 78 // the cyclecounter has wrapped since this packet was received 78 unsigned int cc_seconds=CYCLE_TIMER_GET_SECS(cc); 79 80 81 // the cycletimer has wrapped since this packet was received 79 82 // we want cc_seconds to reflect the 'seconds' at the point this 80 83 // was received … … 83 86 // reconstruct the top part of the timestamp using the current cycle number 84 87 unsigned int now_cycle_masked=cycle & 0xF; 85 unsigned int syt_cycle=CYCLE_ COUNTER_GET_CYCLES(syt_timestamp);88 unsigned int syt_cycle=CYCLE_TIMER_GET_CYCLES(syt_timestamp); 86 89 87 90 // if this is true, wraparound has occurred, undo this wraparound … … 95 98 unsigned int new_cycles=cycle + delta_cycles; 96 99 97 // if the cycles cause a wraparound of the cycle counter,100 // if the cycles cause a wraparound of the cycle timer, 98 101 // perform this wraparound 99 102 if(new_cycles>7999) { … … 113 116 114 117 // and the seconds part 115 // if the timestamp causes a wraparound of the cycle counter,118 // if the timestamp causes a wraparound of the cycle timer, 116 119 // the timestamp lies in the next second 117 120 // if it didn't, the timestamp lies in this second … … 130 133 131 134 // now we reconstruct the presentation time 132 cif.pres_seconds = CYCLE_ COUNTER_GET_SECS(m_full_timestamp);133 cif.pres_cycle = CYCLE_ COUNTER_GET_CYCLES(m_full_timestamp);134 cif.pres_offset = CYCLE_ COUNTER_GET_OFFSET(m_full_timestamp);135 cif.pres_ticks = CYCLE_ COUNTER_TO_TICKS(m_full_timestamp);135 cif.pres_seconds = CYCLE_TIMER_GET_SECS(m_full_timestamp); 136 cif.pres_cycle = CYCLE_TIMER_GET_CYCLES(m_full_timestamp); 137 cif.pres_offset = CYCLE_TIMER_GET_OFFSET(m_full_timestamp); 138 cif.pres_ticks = CYCLE_TIMER_TO_TICKS(m_full_timestamp); 136 139 137 140 if (wraparound_occurred) { branches/streaming-rework/tests/SytMonitor.h
r360 r384 30 30 #include "src/libstreaming/IsoStream.h" 31 31 #include "src/libstreaming/cip.h" 32 #include "src/libstreaming/cycle counter.h"32 #include "src/libstreaming/cycletimer.h" 33 33 #include "src/libstreaming/ringbuffer.h" 34 34 … … 43 43 unsigned int pres_cycle; 44 44 unsigned int pres_offset; 45 u nsigned intpres_ticks;45 uint64_t pres_ticks; 46 46 }; 47 47 … … 66 66 bool putCycleInfo(struct cycle_info *cif); 67 67 68 IsoHandler * getHandler() {return m_handler;}; 69 68 70 protected: 69 71 freebob_ringbuffer_t * m_cinfo_buffer; branches/streaming-rework/tests/test-cycletimer.cpp
r383 r384 32 32 #include <netinet/in.h> 33 33 34 #include "src/libstreaming/cycle counter.h"34 #include "src/libstreaming/cycletimer.h" 35 35 36 36 #include "src/libstreaming/IsoHandler.h" … … 47 47 48 48 DECLARE_GLOBAL_DEBUG_MODULE; 49 IMPL_GLOBAL_DEBUG_MODULE( FreeBoB, DEBUG_LEVEL_VERBOSE );50 49 51 50 int run; … … 77 76 } 78 77 79 int do_cycle counter_test() {80 81 struct CYCLE_TIMER_REGISTER cycle_ counter;82 uint32_t *cycle_ counter_as_uint=(uint32_t *)&cycle_counter;78 int do_cycletimer_test() { 79 80 struct CYCLE_TIMER_REGISTER cycle_timer; 81 uint32_t *cycle_timer_as_uint=(uint32_t *)&cycle_timer; 83 82 84 83 uint32_t i=0; … … 91 90 // 92 91 93 *cycle_ counter_as_uint=0;92 *cycle_timer_as_uint=0; 94 93 for (i=0;i<3072;i++) { 95 cycle_ counter.offset=i;96 targetval=CYCLE_ COUNTER_GET_OFFSET(ctr_to_quadlet(cycle_counter));94 cycle_timer.offset=i; 95 targetval=CYCLE_TIMER_GET_OFFSET(ctr_to_quadlet(cycle_timer)); 97 96 98 97 if(targetval != i) { … … 103 102 104 103 for (i=0;i<8000;i++) { 105 cycle_ counter.cycles=i;106 targetval=CYCLE_ COUNTER_GET_CYCLES(ctr_to_quadlet(cycle_counter));104 cycle_timer.cycles=i; 105 targetval=CYCLE_TIMER_GET_CYCLES(ctr_to_quadlet(cycle_timer)); 107 106 108 107 if(targetval != i) { … … 113 112 114 113 for (i=0;i<128;i++) { 115 cycle_ counter.seconds=i;116 targetval=CYCLE_ COUNTER_GET_SECS(ctr_to_quadlet(cycle_counter));114 cycle_timer.seconds=i; 115 targetval=CYCLE_TIMER_GET_SECS(ctr_to_quadlet(cycle_timer)); 117 116 118 117 if(targetval != i) { … … 123 122 124 123 124 // a value in ticks 125 // should be: 10sec, 1380cy, 640ticks 126 targetval=250000000L; 127 cycle_timer.seconds = TICKS_TO_SECS(targetval); 128 cycle_timer.cycles = TICKS_TO_CYCLES(targetval); 129 cycle_timer.offset = TICKS_TO_OFFSET(targetval); 130 131 if((cycle_timer.seconds != 10) | 132 (cycle_timer.cycles != 1380) | 133 (cycle_timer.offset != 640)) 134 { 135 debugOutput(DEBUG_LEVEL_NORMAL, " test4 failed: (%u,10)sec (%u,1380)cy (%u,640)ticks\n", 136 cycle_timer.seconds,cycle_timer.cycles,cycle_timer.offset); 137 failures++; 138 } else { 139 debugOutput(DEBUG_LEVEL_NORMAL, " test4 ok\n"); 140 } 141 142 i=TICKS_TO_CYCLE_TIMER(targetval); 143 if (i != 0x14564280) { 144 debugOutput(DEBUG_LEVEL_NORMAL, " test5 failed: (0x%08X,0x14564280)\n", 145 i); 146 failures++; 147 } else { 148 debugOutput(DEBUG_LEVEL_NORMAL, " test5 ok\n"); 149 } 150 151 targetval=CYCLE_TIMER_TO_TICKS(i); 152 if (targetval!=250000000L) { 153 debugOutput(DEBUG_LEVEL_NORMAL, " test6 failed: (%u,250000000)\n", 154 targetval); 155 failures++; 156 } else { 157 debugOutput(DEBUG_LEVEL_NORMAL, " test6 ok\n"); 158 } 125 159 126 160 if (failures) { … … 154 188 signal (SIGPIPE, sighandler); 155 189 156 debugOutput(DEBUG_LEVEL_NORMAL, "Freebob Cycle counter test application\n");157 158 debugOutput(DEBUG_LEVEL_NORMAL, "Testing cycle counter helper functions & macro's... \n");159 if(do_cycle counter_test()) {190 debugOutput(DEBUG_LEVEL_NORMAL, "Freebob Cycle timer test application\n"); 191 192 debugOutput(DEBUG_LEVEL_NORMAL, "Testing cycle timer helper functions & macro's... \n"); 193 if(do_cycletimer_test()) { 160 194 debugOutput(DEBUG_LEVEL_NORMAL, " !!! FAILED !!!\n"); 161 195 exit(1); … … 319 353 debugOutput(DEBUG_LEVEL_NORMAL, "Bye...\n"); 320 354 321 delete DebugModuleManager::instance();322 323 355 return EXIT_SUCCESS; 324 356 } branches/streaming-rework/tests/test-sytmonitor.cpp
r383 r384 33 33 #include <netinet/in.h> 34 34 35 #include "src/libstreaming/cycle counter.h"35 #include "src/libstreaming/cycletimer.h" 36 36 37 37 #include "src/libstreaming/IsoHandlerManager.h" … … 39 39 40 40 #include "src/libutil/PosixThread.h" 41 #include "src/libutil/SystemTimeSource.h" 41 42 42 43 #include "pthread.h" … … 45 46 using namespace FreebobUtil; 46 47 48 47 49 DECLARE_GLOBAL_DEBUG_MODULE; 48 IMPL_GLOBAL_DEBUG_MODULE( FreeBoB, DEBUG_LEVEL_VERBOSE );49 50 50 51 int run; … … 159 160 int main(int argc, char *argv[]) 160 161 { 161 int target_port=0;162 int target_channel_1=0;163 int target_channel_2=0;164 162 bool run_realtime=false; 165 163 int realtime_prio=20; … … 167 165 int i; 168 166 struct sched_param params; 167 uint64_t last_print_time=0; 168 169 SystemTimeSource masterTimeSource; 169 170 170 171 IsoHandlerManager *m_isoManager=NULL; … … 172 173 173 174 SytMonitor *monitors[128]; 174 int stream_offset_ticks[128];175 int64_t stream_offset_ticks[128]; 175 176 176 177 struct arguments arguments; … … 245 246 246 247 if(!m_isoManager->registerStream(monitors[i])) { 247 debugOutput(DEBUG_LEVEL_NORMAL, "Could not register SytMonitor %d\n", i); 248 goto finish; 249 } 250 } 251 248 debugOutput(DEBUG_LEVEL_NORMAL, "Could not register SytMonitor %d with isoManager\n", i); 249 goto finish; 250 } 251 252 if (!masterTimeSource.registerSlave(monitors[i]->getHandler())) { 253 debugOutput(DEBUG_LEVEL_NORMAL, "Could not register SytMonitor %d's IsoHandler with masterTimeSource\n", i); 254 goto finish; 255 256 } 257 } 252 258 253 259 debugOutput(DEBUG_LEVEL_NORMAL, "Preparing IsoHandlerManager...\n"); … … 259 265 debugOutput(DEBUG_LEVEL_NORMAL, "Starting ISO manager sync update thread...\n"); 260 266 261 // start the runner thread262 m_isoManagerThread->Start();263 267 264 268 debugOutput(DEBUG_LEVEL_NORMAL, "Starting IsoHandlers...\n"); … … 267 271 goto finish; 268 272 } 273 274 // start the runner thread 275 m_isoManagerThread->Start(); 269 276 270 277 if (arguments.realtime) { … … 278 285 // do the actual work 279 286 nb_iter=0; 287 280 288 while(run) { 281 289 debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"--- Iterate ---\n"); 282 290 283 if(!m_isoManager->iterate()) { 284 debugFatal("Could not iterate the isoManager\n"); 291 // if(!m_isoManager->iterate()) { 292 // debugFatal("Could not iterate the isoManager\n"); 293 // return false; 294 // } 295 296 if(!masterTimeSource.updateTimeSource()) { 297 debugFatal("Could not update the masterTimeSource\n"); 285 298 return false; 286 299 } … … 334 347 // detect seconds wraparound 335 348 if ((master_cif.pres_seconds==0) && (cif.pres_seconds==127)) { 336 master_cif.pres_ticks += TICKS_PER_SECOND*128 ;349 master_cif.pres_ticks += TICKS_PER_SECOND*128LL; 337 350 } 338 351 if ((master_cif.pres_seconds==127) && (cif.pres_seconds==0)) { 339 cif.pres_ticks += TICKS_PER_SECOND*128 ;352 cif.pres_ticks += TICKS_PER_SECOND*128LL; 340 353 } 341 354 // average out the offset 342 int err=(((long)master_cif.pres_ticks) - ((long)cif.pres_ticks));355 int64_t err=(((uint64_t)master_cif.pres_ticks) - ((uint64_t)cif.pres_ticks)); 343 356 344 357 err = err - stream_offset_ticks[i]; … … 357 370 " [%04us %04uc, %04X (%02uc %04ut)]\n", 358 371 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));372 master_cif.syt, CYCLE_TIMER_GET_CYCLES(master_cif.syt), 373 CYCLE_TIMER_GET_OFFSET(master_cif.syt)); 361 374 362 375 debugOutput(DEBUG_LEVEL_NORMAL, … … 368 381 " [%04us %04uc, %04X (%02uc %04ut)]\n", 369 382 cif.seconds,cif.cycle, 370 cif.syt, CYCLE_ COUNTER_GET_CYCLES(cif.syt),371 CYCLE_ COUNTER_GET_OFFSET(cif.syt));383 cif.syt, CYCLE_TIMER_GET_CYCLES(cif.syt), 384 CYCLE_TIMER_GET_OFFSET(cif.syt)); 372 385 debugOutput(DEBUG_LEVEL_NORMAL,"\n"); 373 386 } … … 420 433 421 434 // show info every x iterations 422 if ((nb_iter++ % 4000)==0) { 435 if (masterTimeSource.getCurrentTimeAsUsecs() 436 - last_print_time > 1000000L) { 437 423 438 m_isoManager->dumpInfo(); 424 439 for (i=0;i<arguments.nb_combos;i++) { 425 440 monitors[i]->dumpInfo(); 426 debugOutput(DEBUG_LEVEL_NORMAL," ==> Stream offset: %10d ticks\n",stream_offset_ticks[i]); 441 debugOutputShort(DEBUG_LEVEL_NORMAL," ==> Stream offset: %10lld ticks (%6.4f ms)\n", 442 stream_offset_ticks[i], (1.0*((double)stream_offset_ticks[i]))/24576.0); 427 443 } 428 } 444 masterTimeSource.printTimeSourceInfo(); 445 last_print_time=masterTimeSource.getCurrentTimeAsUsecs(); 446 } 447 448 // 125us/packet, so sleep for a while 449 usleep(100); 429 450 } 430 451 … … 455 476 finish: 456 477 debugOutput(DEBUG_LEVEL_NORMAL, "Bye...\n"); 457 delete DebugModuleManager::instance(); 458 478 459 479 return EXIT_SUCCESS; 460 480 }