template < typename IN_PORT_TYPE, typename OUT_PORT_TYPE > int randomizer_base::_forecastAndProcess( bool &eos, typename std::vector< gr_istream< IN_PORT_TYPE > > &istreams , typename std::vector< gr_ostream< OUT_PORT_TYPE > > &ostreams ) { typedef typename std::vector< gr_istream< IN_PORT_TYPE > > _IStreamList; typedef typename std::vector< gr_ostream< OUT_PORT_TYPE > > _OStreamList; typename _OStreamList::iterator ostream; typename _IStreamList::iterator istream = istreams.begin(); int nout = 0; bool dataReady = false; if ( !eos ) { uint64_t max_items_avail = 0; for ( int idx=0 ; istream != istreams.end() && serviceThread->threadRunning() ; idx++, istream++ ) { LOG_TRACE( randomizer_base, "GET MAX ITEMS: STREAM:"<< idx << " NITEMS/SCALARS:" << istream->nitems() << "/" << istream->_data.size() ); max_items_avail = std::max( istream->nitems(), max_items_avail ); } if ( max_items_avail == 0 ) { LOG_TRACE( randomizer_base, "DATA CHECK - MAX ITEMS NOUTPUT/MAX_ITEMS:" << noutput_items << "/" << max_items_avail); return -1; } // // calc number of output elements based on input items available // noutput_items = 0; if ( !gr_sptr->fixed_rate() ) { noutput_items = round_down((int32_t) (max_items_avail * gr_sptr->relative_rate()), gr_sptr->output_multiple()); LOG_TRACE( randomizer_base, " VARIABLE FORECAST NOUTPUT == " << noutput_items ); } else { istream = istreams.begin(); for ( int i=0; istream != istreams.end(); i++, istream++ ) { int t_noutput_items = gr_sptr->fixed_rate_ninput_to_noutput( istream->nitems() ); if ( gr_sptr->output_multiple_set() ) { t_noutput_items = round_up(t_noutput_items, gr_sptr->output_multiple()); } if ( t_noutput_items > 0 ) { if ( noutput_items == 0 ) { noutput_items = t_noutput_items; } if ( t_noutput_items <= noutput_items ) { noutput_items = t_noutput_items; } } } LOG_TRACE( randomizer_base, " FIXED FORECAST NOUTPUT/output_multiple == " << noutput_items << "/" << gr_sptr->output_multiple()); } // // ask the block how much input they need to produce noutput_items... // if enough data is available to process then set the dataReady flag // int32_t outMultiple = gr_sptr->output_multiple(); while ( !dataReady && noutput_items >= outMultiple ) { // // ask the block how much input they need to produce noutput_items... // gr_sptr->forecast(noutput_items, _ninput_items_required); LOG_TRACE( randomizer_base, "--> FORECAST IN/OUT " << _ninput_items_required[0] << "/" << noutput_items ); istream = istreams.begin(); uint32_t dr_cnt=0; for ( int idx=0 ; noutput_items > 0 && istream != istreams.end(); idx++, istream++ ) { // check if buffer has enough elements _input_ready[idx] = false; if ( istream->nitems() >= (uint64_t)_ninput_items_required[idx] ) { _input_ready[idx] = true; dr_cnt++; } LOG_TRACE( randomizer_base, "ISTREAM DATACHECK NELMS/NITEMS/REQ/READY:" << istream->nelems() << "/" << istream->nitems() << "/" << _ninput_items_required[idx] << "/" << _input_ready[idx]); } if ( dr_cnt < istreams.size() ) { if ( outMultiple > 1 ) { noutput_items -= outMultiple; } else { noutput_items /= 2; } } else { dataReady = true; } LOG_TRACE( randomizer_base, " TRIM FORECAST NOUTPUT/READY " << noutput_items << "/" << dataReady ); } // check if data is ready... if ( !dataReady ) { LOG_TRACE( randomizer_base, "DATA CHECK - NOT ENOUGH DATA AVAIL/REQ:" << _istreams[0].nitems() << "/" << _ninput_items_required[0] ); return -1; } // reset looping variables int ritems = 0; int nitems = 0; // reset caching vectors _output_items.clear(); _input_items.clear(); _ninput_items.clear(); istream = istreams.begin(); for ( int idx=0 ; istream != istreams.end(); idx++, istream++ ) { // check if the stream is ready if ( !_input_ready[idx] ) { continue; } // get number of items remaining try { ritems = gr_sptr->nitems_read( idx ); } catch(...){ // something bad has happened, we are missing an input stream LOG_ERROR( randomizer_base, "MISSING INPUT STREAM FOR GR BLOCK, STREAM ID:" << istream->streamID ); return -2; } nitems = istream->nitems() - ritems; LOG_TRACE( randomizer_base, " ISTREAM: IDX:" << idx << " ITEMS AVAIL/READ/REQ " << nitems << "/" << ritems << "/" << _ninput_items_required[idx] ); if ( nitems >= _ninput_items_required[idx] && nitems > 0 ) { //remove eos checks ...if ( nitems < _ninput_items_required[idx] ) nitems=0; _ninput_items.push_back( nitems ); _input_items.push_back( (const void *) (istream->read_pointer(ritems)) ); } } // // setup output buffer vector based on noutput.. // ostream = ostreams.begin(); for( ; ostream != ostreams.end(); ostream++ ) { ostream->resize(noutput_items); _output_items.push_back((void*)(ostream->write_pointer()) ); } nout=0; if ( _input_items.size() != 0 && serviceThread->threadRunning() ) { LOG_TRACE( randomizer_base, " CALLING WORK.....N_OUT:" << noutput_items << " N_IN:" << nitems << " ISTREAMS:" << _input_items.size() << " OSTREAMS:" << _output_items.size()); nout = gr_sptr->general_work( noutput_items, _ninput_items, _input_items, _output_items); LOG_TRACE( randomizer_base, "RETURN WORK ..... N_OUT:" << nout); } // check for stop condition from work method if ( nout < gr_block::WORK_DONE ) { LOG_WARN( randomizer_base, "WORK RETURNED STOP CONDITION..." << nout ); nout=0; eos = true; } } if (nout != 0 or eos ) { noutput_items = nout; LOG_TRACE( randomizer_base, " WORK RETURNED: NOUT : " << nout << " EOS:" << eos); ostream = ostreams.begin(); typename IN_PORT_TYPE::dataTransfer *pkt=NULL; for ( int idx=0 ; ostream != ostreams.end(); idx++, ostream++ ) { pkt=NULL; int inputIdx = idx; if ( (size_t)(inputIdx) >= istreams.size() ) { for ( inputIdx= istreams.size()-1; inputIdx > -1; inputIdx--) { if ( istreams[inputIdx].pkt != NULL ) { pkt = istreams[inputIdx].pkt; break; } } } else { pkt = istreams[inputIdx].pkt; } LOG_TRACE( randomizer_base, "PUSHING DATA ITEMS/STREAM_ID " << ostream->nitems() << "/" << ostream->streamID ); if ( _maintainTimeStamp ) { // set time stamp for output samples based on input time stamp if ( ostream->nelems() == 0 ) { #ifdef TEST_TIME_STAMP LOG_DEBUG( randomizer_base, "SEED - TS SRI: xdelta:" << std::setprecision(12) << ostream->sri.xdelta ); LOG_DEBUG( randomizer_base, "OSTREAM WRITE: maint:" << _maintainTimeStamp ); LOG_DEBUG( randomizer_base, " mode:" << ostream->tstamp.tcmode ); LOG_DEBUG( randomizer_base, " status:" << ostream->tstamp.tcstatus ); LOG_DEBUG( randomizer_base, " offset:" << ostream->tstamp.toff ); LOG_DEBUG( randomizer_base, " whole:" << std::setprecision(10) << ostream->tstamp.twsec ); LOG_DEBUG( randomizer_base, "SEED - TS frac:" << std::setprecision(12) << ostream->tstamp.tfsec ); #endif ostream->setTimeStamp( pkt->T, _maintainTimeStamp ); } // write out samples, and set next time stamp based on xdelta and noutput_items ostream->write ( noutput_items, eos ); } else { // use incoming packet's time stamp to forward if ( pkt ) { #ifdef TEST_TIME_STAMP LOG_DEBUG( randomizer_base, "OSTREAM SRI: items/xdelta:" << noutput_items << "/" << std::setprecision(12) << ostream->sri.xdelta ); LOG_DEBUG( randomizer_base, "PKT - TS maint:" << _maintainTimeStamp ); LOG_DEBUG( randomizer_base, " mode:" << pkt->T.tcmode ); LOG_DEBUG( randomizer_base, " status:" << pkt->T.tcstatus ); LOG_DEBUG( randomizer_base, " offset:" << pkt->T.toff ); LOG_DEBUG( randomizer_base, " whole:" << std::setprecision(10) << pkt->T.twsec ); LOG_DEBUG( randomizer_base, "PKT - TS frac:" << std::setprecision(12) << pkt->T.tfsec ); #endif ostream->write( noutput_items, eos, pkt->T ); } else { #ifdef TEST_TIME_STAMP LOG_DEBUG( randomizer_base, "OSTREAM SRI: items/xdelta:" << noutput_items << "/" << std::setprecision(12) << ostream->sri.xdelta ); LOG_DEBUG( randomizer_base, "OSTREAM TOD maint:" << _maintainTimeStamp ); LOG_DEBUG( randomizer_base, " mode:" << ostream->tstamp.tcmode ); LOG_DEBUG( randomizer_base, " status:" << ostream->tstamp.tcstatus ); LOG_DEBUG( randomizer_base, " offset:" << ostream->tstamp.toff ); LOG_DEBUG( randomizer_base, " whole:" << std::setprecision(10) << ostream->tstamp.twsec ); LOG_DEBUG( randomizer_base, "OSTREAM TOD frac:" << std::setprecision(12) << ostream->tstamp.tfsec ); #endif // use time of day as time stamp ostream->write( noutput_items, eos, _maintainTimeStamp ); } } } // for ostreams } return nout; }
template < typename IN_PORT_TYPE > int file_descriptor_sink_i_base::_forecastAndProcess( bool &eos, typename std::vector< gr_istream< IN_PORT_TYPE > > &istreams ) { typedef typename std::vector< gr_istream< IN_PORT_TYPE > > _IStreamList; typename _IStreamList::iterator istream = istreams.begin(); int nout = 0; bool dataReady = false; if ( !eos ) { uint64_t max_items_avail = 0; for ( int idx=0 ; istream != istreams.end() && serviceThread->threadRunning() ; idx++, istream++ ) { LOG_TRACE( file_descriptor_sink_i_base, "GET MAX ITEMS: STREAM:" << idx << " NITEMS/SCALARS:" << istream->nitems() << "/" << istream->_data.size() ); max_items_avail = std::max( istream->nitems(), max_items_avail ); } // // calc number of output items to produce // noutput_items = (int) (max_items_avail * gr_sptr->relative_rate ()); noutput_items = round_down (noutput_items, gr_sptr->output_multiple ()); if ( noutput_items <= 0 ) { LOG_TRACE( file_descriptor_sink_i_base, "DATA CHECK - MAX ITEMS NOUTPUT/MAX_ITEMS:" << noutput_items << "/" << max_items_avail); return -1; } if ( gr_sptr->fixed_rate() ) { istream = istreams.begin(); for ( int i=0; istream != istreams.end(); i++, istream++ ) { int t_noutput_items = gr_sptr->fixed_rate_ninput_to_noutput( istream->nitems() ); if ( gr_sptr->output_multiple_set() ) { t_noutput_items = round_up(t_noutput_items, gr_sptr->output_multiple()); } if ( t_noutput_items > 0 ) { if ( noutput_items == 0 ) { noutput_items = t_noutput_items; } if ( t_noutput_items <= noutput_items ) { noutput_items = t_noutput_items; } } } LOG_TRACE( file_descriptor_sink_i_base, " FIXED FORECAST NOUTPUT/output_multiple == " << noutput_items << "/" << gr_sptr->output_multiple()); } // // ask the block how much input they need to produce noutput_items... // if enough data is available to process then set the dataReady flag // int32_t outMultiple = gr_sptr->output_multiple(); while ( !dataReady && noutput_items >= outMultiple ) { // // ask the block how much input they need to produce noutput_items... // gr_sptr->forecast(noutput_items, _ninput_items_required); LOG_TRACE( file_descriptor_sink_i_base, "--> FORECAST IN/OUT " << _ninput_items_required[0] << "/" << noutput_items ); istream = istreams.begin(); uint32_t dr_cnt=0; for ( int idx=0 ; noutput_items > 0 && istream != istreams.end(); idx++, istream++ ) { // check if buffer has enough elements _input_ready[idx] = false; if ( istream->nitems() >= (uint64_t)_ninput_items_required[idx] ) { _input_ready[idx] = true; dr_cnt++; } LOG_TRACE( file_descriptor_sink_i_base, "ISTREAM DATACHECK NELMS/NITEMS/REQ/READY:" << istream->nelems() << "/" << istream->nitems() << "/" << _ninput_items_required[idx] << "/" << _input_ready[idx]); } if ( dr_cnt < istreams.size() ) { if ( outMultiple > 1 ) { noutput_items -= outMultiple; } else { noutput_items /= 2; } } else { dataReady = true; } LOG_TRACE( file_descriptor_sink_i_base, " TRIM FORECAST NOUTPUT/READY " << noutput_items << "/" << dataReady ); } // check if data is ready... if ( !dataReady ) { LOG_TRACE( file_descriptor_sink_i_base, "DATA CHECK - NOT ENOUGH DATA AVAIL/REQ:" << _istreams[0].nitems() << "/" << _ninput_items_required[0] ); return -1; } // reset looping variables int ritems = 0; int nitems = 0; // reset caching vectors _output_items.clear(); _input_items.clear(); _ninput_items.clear(); istream = istreams.begin(); for ( int idx=0 ; istream != istreams.end(); idx++, istream++ ) { // check if the stream is ready if ( !_input_ready[idx] ) continue; // get number of items remaining try { ritems = gr_sptr->nitems_read( idx ); } catch(...){ // something bad has happened, we are missing an input stream LOG_ERROR( file_descriptor_sink_i_base, "MISSING INPUT STREAM FOR GR BLOCK, STREAM ID:" << istream->streamID ); return -2; } nitems = istream->nitems() - ritems; LOG_TRACE( file_descriptor_sink_i_base, " ISTREAM: IDX:" << idx << " ITEMS AVAIL/READ/REQ " << nitems << "/" << ritems << "/" << _ninput_items_required[idx] ); if ( nitems >= _ninput_items_required[idx] && nitems > 0 ) { //remove eos checks ...if ( nitems < _ninput_items_required[idx] ) nitems=0; _ninput_items.push_back( nitems ); _input_items.push_back( (const void *) (istream->read_pointer(ritems)) ); } } nout=0; if ( _input_items.size() != 0 && serviceThread->threadRunning() ) { LOG_TRACE( file_descriptor_sink_i_base, " CALLING WORK.....N_OUT:" << noutput_items << " N_IN:" << nitems << " ISTREAMS:" << _input_items.size() << " OSTREAMS:" << _output_items.size()); nout = gr_sptr->general_work( noutput_items, _ninput_items, _input_items, _output_items); // sink/analyzer patterns do not return items, so consume_each is not called in Gnu Radio BLOCK if ( nout == 0 ) { gr_sptr->consume_each(nitems); } LOG_TRACE( file_descriptor_sink_i_base, "RETURN WORK ..... N_OUT:" << nout); } // check for stop condition from work method if ( nout < gr_block::WORK_DONE ) { LOG_WARN( file_descriptor_sink_i_base, "WORK RETURNED STOP CONDITION..." << nout ); nout=0; eos = true; } } return nout; }
template < typename IN_PORT_TYPE, typename OUT_PORT_TYPE > int randomizer_base::_transformerServiceFunction( typename std::vector< gr_istream< IN_PORT_TYPE > > &istreams , typename std::vector< gr_ostream< OUT_PORT_TYPE > > &ostreams ) { typedef typename std::vector< gr_istream< IN_PORT_TYPE > > _IStreamList; typedef typename std::vector< gr_ostream< OUT_PORT_TYPE > > _OStreamList; boost::mutex::scoped_lock lock(serviceThreadLock); if ( validGRBlock() == false ) { // create our processing block, and setup property notifiers createBlock(); LOG_DEBUG( randomizer_base, " FINISHED BUILDING GNU RADIO BLOCK"); } //process any Stream ID changes this could affect number of io streams processStreamIdChanges(); if ( !validGRBlock() || istreams.size() == 0 || ostreams.size() == 0 ) { LOG_WARN( randomizer_base, "NO STREAMS ATTACHED TO BLOCK..." ); return NOOP; } _input_ready.resize( istreams.size() ); _ninput_items_required.resize( istreams.size() ); _ninput_items.resize( istreams.size() ); _input_items.resize( istreams.size() ); _output_items.resize( ostreams.size() ); // // RESOLVE: need to look at forecast strategy, // 1) see how many read items are necessary for N number of outputs // 2) read input data and see how much output we can produce // // // Grab available data from input streams // typename _OStreamList::iterator ostream; typename _IStreamList::iterator istream = istreams.begin(); int nitems=0; for ( int idx=0 ; istream != istreams.end() && serviceThread->threadRunning() ; idx++, istream++ ) { // note this a blocking read that can cause deadlocks nitems = istream->read(); if ( istream->overrun() ) { LOG_WARN( randomizer_base, " NOT KEEPING UP WITH STREAM ID:" << istream->streamID ); } if ( istream->sriChanged() ) { // RESOLVE - need to look at how SRI changes can affect Gnu Radio BLOCK state LOG_DEBUG( randomizer_base, "SRI CHANGED, STREAMD IDX/ID: " << idx << "/" << istream->pkt->streamID ); setOutputStreamSRI( idx, istream->pkt->SRI ); } } LOG_TRACE( randomizer_base, "READ NITEMS: " << nitems ); if ( nitems <= 0 && !_istreams[0].eos() ) { return NOOP; } bool eos = false; int nout = 0; bool workDone = false; while ( nout > -1 && serviceThread->threadRunning() ) { eos = false; nout = _forecastAndProcess( eos, istreams, ostreams ); if ( nout > -1 ) { workDone = true; // we chunked on data so move read pointer.. istream = istreams.begin(); for ( ; istream != istreams.end(); istream++ ) { int idx=std::distance( istreams.begin(), istream ); // if we processed data for this stream if ( _input_ready[idx] ) { size_t nitems = 0; try { nitems = gr_sptr->nitems_read( idx ); } catch(...){} if ( nitems > istream->nitems() ) { LOG_WARN( randomizer_base, "WORK CONSUMED MORE DATA THAN AVAILABLE, READ/AVAILABLE " << nitems << "/" << istream->nitems() ); nitems = istream->nitems(); } istream->consume( nitems ); LOG_TRACE( randomizer_base, " CONSUME READ DATA ITEMS/REMAIN " << nitems << "/" << istream->nitems()); } } gr_sptr->reset_read_index(); } // check for not enough data return if ( nout == -1 ) { // check for end of stream istream = istreams.begin(); for ( ; istream != istreams.end() ; istream++) { if ( istream->eos() ) { eos=true; } } if ( eos ) { LOG_TRACE( randomizer_base, "EOS SEEN, SENDING DOWNSTREAM " ); _forecastAndProcess( eos, istreams, ostreams); } } } if ( eos ) { istream = istreams.begin(); for ( ; istream != istreams.end() ; istream++ ) { int idx=std::distance( istreams.begin(), istream ); LOG_DEBUG( randomizer_base, " CLOSING INPUT STREAM IDX:" << idx ); istream->close(); } // close remaining output streams ostream = ostreams.begin(); for ( ; eos && ostream != ostreams.end(); ostream++ ) { int idx=std::distance( ostreams.begin(), ostream ); LOG_DEBUG( randomizer_base, " CLOSING OUTPUT STREAM IDX:" << idx ); ostream->close(); } } // // set the read pointers of the GNU Radio Block to start at the beginning of the // supplied buffers // gr_sptr->reset_read_index(); LOG_TRACE( randomizer_base, " END OF TRANSFORM SERVICE FUNCTION....." << noutput_items ); if ( nout == -1 && eos == false && !workDone ) { return NOOP; } else { return NORMAL; } }
template < typename IN_PORT_TYPE > int vector_sink_s_base::_analyzerServiceFunction( typename std::vector< gr_istream< IN_PORT_TYPE > > &istreams ) { typedef typename std::vector< gr_istream< IN_PORT_TYPE > > _IStreamList; boost::mutex::scoped_lock lock(serviceThreadLock); if ( validGRBlock() == false ) { // create our processing block createBlock(); LOG_DEBUG( vector_sink_s_base, " FINISHED BUILDING GNU RADIO BLOCK"); } // process any Stream ID changes this could affect number of io streams processStreamIdChanges(); if ( !validGRBlock() || istreams.size() == 0 ) { LOG_WARN(vector_sink_s_base, "NO STREAMS ATTACHED TO BLOCK..." ); return NOOP; } // resize data vectors for passing data to GR_BLOCK object _input_ready.resize( istreams.size() ); _ninput_items_required.resize( istreams.size()); _ninput_items.resize( istreams.size()); _input_items.resize(istreams.size()); _output_items.resize(0); // // RESOLVE: need to look at forecast strategy, // 1) see how many read items are necessary for N number of outputs // 2) read input data and see how much output we can produce // // // Grab available data from input streams // typename _IStreamList::iterator istream = istreams.begin(); int nitems=0; for ( int idx=0 ; istream != istreams.end() && serviceThread->threadRunning() ; idx++, istream++ ) { // note this a blocking read that can cause deadlocks nitems = istream->read(); if ( istream->overrun() ) { LOG_WARN( vector_sink_s_base, " NOT KEEPING UP WITH STREAM ID:" << istream->streamID ); } // RESOLVE issue when SRI changes that could affect the GNU Radio BLOCK if ( istream->sriChanged() ) { LOG_DEBUG( vector_sink_s_base, "SRI CHANGED, STREAMD IDX/ID: " << idx << "/" << istream->pkt->streamID ); } } LOG_TRACE( vector_sink_s_base, "READ NITEMS: " << nitems ); if ( nitems <= 0 && !_istreams[0].eos() ) return NOOP; bool exitServiceFunction = false; bool eos = false; int nout = 0; while ( nout > -1 && !exitServiceFunction && serviceThread->threadRunning() ) { eos = false; nout = _forecastAndProcess( eos, istreams ); if ( nout > -1 ) { // we chunked on data so move read pointer.. istream = istreams.begin(); for ( ; istream != istreams.end(); istream++ ) { int idx=std::distance( istreams.begin(), istream ); // if we processed data for this stream if ( _input_ready[idx] ) { size_t nitems = 0; try { nitems = gr_sptr->nitems_read( idx ); } catch(...){} if ( nitems > istream->nitems() ) { LOG_WARN( vector_sink_s_base, "WORK CONSUMED MORE DATA THAN AVAILABLE, READ/AVAILABLE " << nitems << "/" << istream->nitems() ); nitems = istream->nitems(); } istream->consume( nitems ); LOG_TRACE( vector_sink_s_base, " CONSUME READ DATA ITEMS/REMAIN " << nitems << "/" << istream->nitems()); } } gr_sptr->reset_read_index(); } // check for not enough data return if ( nout == -1 ) { // check for end of stream istream = istreams.begin(); for ( ; istream != istreams.end() ; istream++) if ( istream->eos() ) eos=true; if ( eos ) { LOG_TRACE( vector_sink_s_base, " DATA NOT READY, EOS:" << eos ); _forecastAndProcess( eos, istreams ); } exitServiceFunction = true; } } if ( eos ) { istream = istreams.begin(); for ( ; istream != istreams.end() ; istream++) { int idx=std::distance( istreams.begin(), istream ); LOG_TRACE( vector_sink_s_base, " CLOSING INPUT STREAM IDX:" << idx ); istream->close(); } } // // set the read pointers of the GNU Radio Block to start at the beginning of the // supplied buffers // gr_sptr->reset_read_index(); LOG_TRACE( vector_sink_s_base, " END OF ANALYZER SERVICE FUNCTION....." << noutput_items ); if ( nout == -1 && eos == false ) return NOOP; else return NORMAL; }