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);
    }
Exemple #3
0
    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);
    }