void work(void) { auto inPort = this->input(0); auto outPort = this->output(0); inPort->setReserve(_mod); //handle packet conversion if applicable if (inPort->hasMessage()) { auto msg = inPort->popMessage(); if (msg.type() == typeid(Pothos::Packet)) this->msgWork(msg.extract<Pothos::Packet>()); else outPort->postMessage(msg); return; //output buffer used, return now } //calculate work size const size_t numSyms = std::min(inPort->elements() / _mod, outPort->elements()); if (numSyms == 0) return; //perform conversion auto in = inPort->buffer().as<const unsigned char *>(); auto out = outPort->buffer().as<unsigned char *>(); switch (_order) { case MSBit: ::bitsToSymbolsMSBit(_mod, in, out, numSyms); break; case LSBit: ::bitsToSymbolsLSBit(_mod, in, out, numSyms); break; } //produce/consume inPort->consume(numSyms * _mod); outPort->produce(numSyms); }
/******************************************************************* * start frame operation mode work: * The implementation was sufficiently different to separate. ******************************************************************/ void startFrameModeWork(void) { auto inputPort = this->input(0); auto outputPort = this->output(0); //get input buffer auto inBuff = inputPort->buffer(); if (inBuff.length == 0) return; bool frameFound = false; Pothos::Packet packet; packet.payload = inBuff; size_t outputLength = _mtu; auto inLen = inBuff.length; for (auto &label : inputPort->labels()) { // Skip any label that doesn't yet appear in the data buffer if (label.index >= inLen) continue; // Skip any label that isn't a frame start label if (label.id != _frameStartId) continue; //use the label's length when specified if (label.data.canConvert(typeid(size_t))) { outputLength = label.data.convert<size_t>(); outputLength *= label.width; //expand for width outputLength *= inBuff.dtype.size(); //convert to bytes } // Skip all of data before the start of packet if this is the first time we see the label if (label.index != 0) { inputPort->consume(label.index); inputPort->setReserve(outputLength); return; } // This case happens when the start of frame is naturally aligned with the begining of a buffer, but we didn't get enough data // In that case we wait if (inLen < outputLength) { inputPort->setReserve(outputLength); return; } //found! start of frame on index 0 frameFound = true; break; } // Skip all of the data in case we didn't see any frame labels if (not frameFound) { inputPort->consume(inLen); return; } //load non-frame start labels into the packet size_t nextFrameIndex = 0; for (auto &label : inputPort->labels()) { if (label.index >= outputLength) continue; if (label.id == _frameStartId) { if (nextFrameIndex == 0) { nextFrameIndex = label.index; } continue; } packet.labels.push_back(label); } //produce the output packet packet.payload.length = outputLength; outputPort->postMessage(packet); inputPort->setReserve(0); //clear reserve for next packet //consume the input, stopping at the next frame label (in the case of overlap) inputPort->consume((nextFrameIndex != 0)?nextFrameIndex:outputLength); }
void work(void) { if (_waitTapsArmed) return; auto inPort = this->input(0); auto outPort = this->output(0); auto inputAvailable = inPort->elements(); if (inputAvailable == 0) return; /*************************************************************** * search for burst labels and record the next end of burst **************************************************************/ if (_eobSampsLeft == 0) for (const auto &label : inPort->labels()) { if (not _frameStartId.empty() and label.id == _frameStartId and label.data.canConvert(typeid(size_t))) { const auto length = label.data.template convert<size_t>(); _eobSampsLeft = label.index + length*label.width; break; } else if (not _frameEndId.empty() and label.id == _frameEndId) { _eobSampsLeft = label.index + label.width; break; } } /*************************************************************** * check that the available input is sufficient **************************************************************/ //in burst mode, make sure input available stops at the end if (_eobSampsLeft != 0) { if (_eobSampsLeft <= inputAvailable) { inputAvailable = _eobSampsLeft; } else { inPort->setReserve(_eobSampsLeft); return; } } //otherwise insufficient input for the regular streaming mode else if (inputAvailable < _inputRequire) { inPort->setReserve(_inputRequire); return; } //normally we don't enforce a requirement unless there is a problem inPort->setReserve(0); /*************************************************************** * Special input buffer to flush the burst **************************************************************/ auto inBuff = inPort->buffer(); inBuff.length = inputAvailable*sizeof(InType); if (_eobSampsLeft != 0 and _eobSampsLeft < _inputRequire) { const size_t numBytesCopy = _eobSampsLeft*sizeof(InType); Pothos::BufferChunk flushBuff(typeid(InType), _eobSampsLeft + K - 1); std::memcpy(flushBuff.as<void *>(), inBuff.template as<const void *>(), numBytesCopy); std::memset(flushBuff.as<char *>() + numBytesCopy, 0, flushBuff.length-numBytesCopy); inBuff = flushBuff; } /*************************************************************** * Normal FIR filter operation **************************************************************/ //how many iterations? const auto N = std::min((inBuff.elements()-(K-1))/M, outPort->elements()/L); //grab pointers auto x = inBuff.template as<const InType *>() + (K-1); auto y = outPort->buffer().template as<OutType *>(); //for each decimated input for (size_t n = 0; n < N; n++) { //interpolation loop for (size_t j = 0; j < L; j++) { //convolution loop OutType y_n = 0; for (size_t k = 0; k < _interpTaps[j].size(); k++) { y_n += _interpTaps[j][k] * x[n*M-k]; } y[j+n*L] = y_n; } } //consume decimated, produce interpolated //K-1 elements are left in the input buffer for filter history if (_eobSampsLeft != 0) _eobSampsLeft -= N*M; inPort->consume(N*M); outPort->produce(N*L); }