mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-11-03 13:11:20 -05:00 
			
		
		
		
	SDRdaemonFEC: removed useless devices/sdrdaemonfec subdirectory
This commit is contained in:
		
							parent
							
								
									e7b7e77d4d
								
							
						
					
					
						commit
						c2d9e64c0b
					
				@ -1,55 +0,0 @@
 | 
			
		||||
project(sdrdaemondevice)
 | 
			
		||||
 | 
			
		||||
if (HAS_SSSE3)
 | 
			
		||||
    message(STATUS "SDRdaemonDevice: use SSSE3 SIMD" )
 | 
			
		||||
elseif (HAS_NEON)
 | 
			
		||||
    message(STATUS "SDRdaemonDevice: use Neon SIMD" )
 | 
			
		||||
else()
 | 
			
		||||
    message(STATUS "SDRdaemonDevice: Unsupported architecture")
 | 
			
		||||
    return()
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
set(sdrdaemondevice_SOURCES
 | 
			
		||||
    sdrdaemonfecbuffer.cpp
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set(sdrdaemondevice_HEADERS
 | 
			
		||||
    sdrdaemonfecbuffer.h
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
add_definitions(${QT_DEFINITIONS})
 | 
			
		||||
add_definitions(-DQT_SHARED)
 | 
			
		||||
 | 
			
		||||
if (BUILD_DEBIAN)
 | 
			
		||||
include_directories(
 | 
			
		||||
    .
 | 
			
		||||
    ${CMAKE_CURRENT_BINARY_DIR}
 | 
			
		||||
    ${LIBCM256CCSRC}
 | 
			
		||||
)
 | 
			
		||||
else (BUILD_DEBIAN)
 | 
			
		||||
include_directories(
 | 
			
		||||
    .
 | 
			
		||||
    ${CMAKE_CURRENT_BINARY_DIR}
 | 
			
		||||
    ${CM256CC_INCLUDE_DIR}
 | 
			
		||||
)
 | 
			
		||||
endif (BUILD_DEBIAN)
 | 
			
		||||
 | 
			
		||||
add_library(sdrdaemondevice SHARED
 | 
			
		||||
    ${sdrdaemondevice_SOURCES}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
if (BUILD_DEBIAN)
 | 
			
		||||
target_link_libraries(sdrdaemondevice
 | 
			
		||||
    ${QT_LIBRARIES}    
 | 
			
		||||
    cm256cc
 | 
			
		||||
)
 | 
			
		||||
else (BUILD_DEBIAN)
 | 
			
		||||
target_link_libraries(sdrdaemondevice
 | 
			
		||||
    ${QT_LIBRARIES}
 | 
			
		||||
    ${CM256CC_LIBRARIES}
 | 
			
		||||
)
 | 
			
		||||
endif (BUILD_DEBIAN)
 | 
			
		||||
 | 
			
		||||
qt5_use_modules(sdrdaemondevice Core)
 | 
			
		||||
 | 
			
		||||
install(TARGETS sdrdaemondevice DESTINATION lib)
 | 
			
		||||
@ -1,377 +0,0 @@
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Copyright (C) 2016 Edouard Griffiths, F4EXB                                   //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// This program is free software; you can redistribute it and/or modify          //
 | 
			
		||||
// it under the terms of the GNU General Public License as published by          //
 | 
			
		||||
// the Free Software Foundation as version 3 of the License, or                  //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// This program is distributed in the hope that it will be useful,               //
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | 
			
		||||
// GNU General Public License V3 for more details.                               //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// You should have received a copy of the GNU General Public License             //
 | 
			
		||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
#include <cassert>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <cmath>
 | 
			
		||||
#include <boost/crc.hpp>
 | 
			
		||||
#include <boost/cstdint.hpp>
 | 
			
		||||
 | 
			
		||||
#include "sdrdaemonfecbuffer.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const int SDRdaemonFECBuffer::m_sampleSize = 2;
 | 
			
		||||
const int SDRdaemonFECBuffer::m_iqSampleSize = 2 * m_sampleSize;
 | 
			
		||||
 | 
			
		||||
SDRdaemonFECBuffer::SDRdaemonFECBuffer(uint32_t throttlems) :
 | 
			
		||||
        m_decoderIndexHead(nbDecoderSlots/2),
 | 
			
		||||
        m_frameHead(0),
 | 
			
		||||
        m_curNbBlocks(0),
 | 
			
		||||
        m_minNbBlocks(256),
 | 
			
		||||
        m_curOriginalBlocks(0),
 | 
			
		||||
        m_minOriginalBlocks(128),
 | 
			
		||||
        m_curNbRecovery(0),
 | 
			
		||||
        m_maxNbRecovery(0),
 | 
			
		||||
        m_framesDecoded(true),
 | 
			
		||||
        m_readIndex(0),
 | 
			
		||||
        m_throttlemsNominal(throttlems),
 | 
			
		||||
        m_readBuffer(0),
 | 
			
		||||
        m_readSize(0),
 | 
			
		||||
        m_bufferLenSec(0.0f),
 | 
			
		||||
        m_nbReads(0),
 | 
			
		||||
        m_nbWrites(0),
 | 
			
		||||
        m_balCorrection(0),
 | 
			
		||||
	    m_balCorrLimit(0)
 | 
			
		||||
{
 | 
			
		||||
	m_currentMeta.init();
 | 
			
		||||
	m_framesNbBytes = nbDecoderSlots * sizeof(BufferFrame);
 | 
			
		||||
	m_wrDeltaEstimate = m_framesNbBytes / 2;
 | 
			
		||||
	m_tvOut_sec = 0;
 | 
			
		||||
	m_tvOut_usec = 0;
 | 
			
		||||
	m_readNbBytes = 1;
 | 
			
		||||
    m_paramsCM256.BlockBytes = sizeof(ProtectedBlock); // never changes
 | 
			
		||||
    m_paramsCM256.OriginalCount = m_nbOriginalBlocks;  // never changes
 | 
			
		||||
 | 
			
		||||
    if (!m_cm256.isInitialized()) {
 | 
			
		||||
        m_cm256_OK = false;
 | 
			
		||||
        qDebug() << "SDRdaemonFECBuffer::SDRdaemonFECBuffer: cannot initialize CM256 library";
 | 
			
		||||
    } else {
 | 
			
		||||
        m_cm256_OK = true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SDRdaemonFECBuffer::~SDRdaemonFECBuffer()
 | 
			
		||||
{
 | 
			
		||||
	if (m_readBuffer) {
 | 
			
		||||
		delete[] m_readBuffer;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SDRdaemonFECBuffer::initDecodeAllSlots()
 | 
			
		||||
{
 | 
			
		||||
    for (int i = 0; i < nbDecoderSlots; i++)
 | 
			
		||||
    {
 | 
			
		||||
        m_decoderSlots[i].m_blockCount = 0;
 | 
			
		||||
        m_decoderSlots[i].m_originalCount = 0;
 | 
			
		||||
        m_decoderSlots[i].m_recoveryCount = 0;
 | 
			
		||||
        m_decoderSlots[i].m_decoded = false;
 | 
			
		||||
        m_decoderSlots[i].m_metaRetrieved = false;
 | 
			
		||||
        resetOriginalBlocks(i);
 | 
			
		||||
        memset((void *) m_decoderSlots[i].m_recoveryBlocks, 0, m_nbOriginalBlocks * sizeof(ProtectedBlock));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SDRdaemonFECBuffer::initDecodeSlot(int slotIndex)
 | 
			
		||||
{
 | 
			
		||||
    // collect stats before voiding the slot
 | 
			
		||||
 | 
			
		||||
    m_curNbBlocks = m_decoderSlots[slotIndex].m_blockCount;
 | 
			
		||||
    m_curOriginalBlocks = m_decoderSlots[slotIndex].m_originalCount;
 | 
			
		||||
    m_curNbRecovery = m_decoderSlots[slotIndex].m_recoveryCount;
 | 
			
		||||
    m_avgNbBlocks(m_curNbBlocks);
 | 
			
		||||
    m_avgOrigBlocks(m_curOriginalBlocks);
 | 
			
		||||
    m_avgNbRecovery(m_curNbRecovery);
 | 
			
		||||
    m_framesDecoded = m_framesDecoded && m_decoderSlots[slotIndex].m_decoded;
 | 
			
		||||
 | 
			
		||||
    if (m_curNbBlocks < m_minNbBlocks) {
 | 
			
		||||
        m_minNbBlocks = m_curNbBlocks;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (m_curOriginalBlocks < m_minOriginalBlocks) {
 | 
			
		||||
        m_minOriginalBlocks = m_curOriginalBlocks;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (m_curNbRecovery > m_maxNbRecovery) {
 | 
			
		||||
        m_maxNbRecovery = m_curNbRecovery;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // void the slot
 | 
			
		||||
 | 
			
		||||
    m_decoderSlots[slotIndex].m_blockCount = 0;
 | 
			
		||||
    m_decoderSlots[slotIndex].m_originalCount = 0;
 | 
			
		||||
    m_decoderSlots[slotIndex].m_recoveryCount = 0;
 | 
			
		||||
    m_decoderSlots[slotIndex].m_decoded = false;
 | 
			
		||||
    m_decoderSlots[slotIndex].m_metaRetrieved = false;
 | 
			
		||||
 | 
			
		||||
    resetOriginalBlocks(slotIndex);
 | 
			
		||||
    memset((void *) m_decoderSlots[slotIndex].m_recoveryBlocks, 0, m_nbOriginalBlocks * sizeof(ProtectedBlock));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SDRdaemonFECBuffer::initReadIndex()
 | 
			
		||||
{
 | 
			
		||||
    m_readIndex = ((m_decoderIndexHead + (nbDecoderSlots/2)) % nbDecoderSlots) * sizeof(BufferFrame);
 | 
			
		||||
    m_wrDeltaEstimate = m_framesNbBytes / 2;
 | 
			
		||||
    m_nbReads = 0;
 | 
			
		||||
    m_nbWrites = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SDRdaemonFECBuffer::rwCorrectionEstimate(int slotIndex)
 | 
			
		||||
{
 | 
			
		||||
	if (m_nbReads >= 40) // check every ~1s as tick is ~50ms
 | 
			
		||||
	{
 | 
			
		||||
		int targetPivotSlot = (slotIndex + (nbDecoderSlots/2))  % nbDecoderSlots; // slot at half buffer opposite of current write slot
 | 
			
		||||
		int targetPivotIndex = targetPivotSlot * sizeof(BufferFrame);             // buffer index corresponding to start of above slot
 | 
			
		||||
		uint32_t normalizedReadIndex = (m_readIndex < targetPivotIndex ? m_readIndex + nbDecoderSlots * sizeof(BufferFrame) :  m_readIndex)
 | 
			
		||||
				- (targetPivotSlot * sizeof(BufferFrame)); // normalize read index so it is positive and zero at start of pivot slot
 | 
			
		||||
		int dBytes;
 | 
			
		||||
        int rwDelta = (m_nbReads * m_readNbBytes) - (m_nbWrites * sizeof(BufferFrame));
 | 
			
		||||
 | 
			
		||||
		if (normalizedReadIndex < (nbDecoderSlots/ 2) * sizeof(BufferFrame)) // read leads
 | 
			
		||||
		{
 | 
			
		||||
			dBytes = - normalizedReadIndex - rwDelta;
 | 
			
		||||
		}
 | 
			
		||||
		else // read lags
 | 
			
		||||
		{
 | 
			
		||||
			dBytes = (nbDecoderSlots * sizeof(BufferFrame)) - normalizedReadIndex - rwDelta;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        m_balCorrection = (m_balCorrection / 4) + (dBytes / (int) (m_iqSampleSize * m_nbReads)); // correction is in number of samples. Alpha = 0.25
 | 
			
		||||
 | 
			
		||||
        if (m_balCorrection < -m_balCorrLimit) {
 | 
			
		||||
            m_balCorrection = -m_balCorrLimit;
 | 
			
		||||
        } else if (m_balCorrection > m_balCorrLimit) {
 | 
			
		||||
            m_balCorrection = m_balCorrLimit;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
	    m_nbReads = 0;
 | 
			
		||||
	    m_nbWrites = 0;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SDRdaemonFECBuffer::checkSlotData(int slotIndex)
 | 
			
		||||
{
 | 
			
		||||
    int pseudoWriteIndex = slotIndex * sizeof(BufferFrame);
 | 
			
		||||
    m_wrDeltaEstimate = pseudoWriteIndex - m_readIndex;
 | 
			
		||||
    m_nbWrites++;
 | 
			
		||||
 | 
			
		||||
    int rwDelayBytes = (m_wrDeltaEstimate > 0 ? m_wrDeltaEstimate : sizeof(BufferFrame) * nbDecoderSlots + m_wrDeltaEstimate);
 | 
			
		||||
    int sampleRate = m_currentMeta.m_sampleRate;
 | 
			
		||||
 | 
			
		||||
    if (sampleRate > 0)
 | 
			
		||||
    {
 | 
			
		||||
        int64_t ts = m_currentMeta.m_tv_sec * 1000000LL + m_currentMeta.m_tv_usec;
 | 
			
		||||
        ts -= (rwDelayBytes * 1000000LL) / (sampleRate * sizeof(Sample));
 | 
			
		||||
        m_tvOut_sec = ts / 1000000LL;
 | 
			
		||||
        m_tvOut_usec = ts - (m_tvOut_sec * 1000000LL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!m_decoderSlots[slotIndex].m_decoded)
 | 
			
		||||
    {
 | 
			
		||||
        qDebug() << "SDRdaemonFECBuffer::checkSlotData: incomplete frame:"
 | 
			
		||||
                << " m_blockCount: " << m_decoderSlots[slotIndex].m_blockCount
 | 
			
		||||
                << " m_recoveryCount: " << m_decoderSlots[slotIndex].m_recoveryCount;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SDRdaemonFECBuffer::writeData(char *array)
 | 
			
		||||
{
 | 
			
		||||
    SuperBlock *superBlock = (SuperBlock *) array;
 | 
			
		||||
    int frameIndex = superBlock->header.frameIndex;
 | 
			
		||||
    int decoderIndex = frameIndex % nbDecoderSlots;
 | 
			
		||||
 | 
			
		||||
    // frame break
 | 
			
		||||
 | 
			
		||||
    if (m_frameHead == -1) // initial state
 | 
			
		||||
    {
 | 
			
		||||
        m_decoderIndexHead = decoderIndex; // new decoder slot head
 | 
			
		||||
        m_frameHead = frameIndex;
 | 
			
		||||
        initReadIndex(); // reset read index
 | 
			
		||||
        initDecodeAllSlots(); // initialize all slots
 | 
			
		||||
    }
 | 
			
		||||
    else if (m_frameHead != frameIndex) // frame break => new frame starts
 | 
			
		||||
    {
 | 
			
		||||
        m_decoderIndexHead = decoderIndex; // new decoder slot head
 | 
			
		||||
        m_frameHead = frameIndex;          // new frame head
 | 
			
		||||
        checkSlotData(decoderIndex);       // check slot before re-init
 | 
			
		||||
        rwCorrectionEstimate(decoderIndex);
 | 
			
		||||
        initDecodeSlot(decoderIndex);      // collect stats and re-initialize current slot
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Block processing
 | 
			
		||||
 | 
			
		||||
    if (m_decoderSlots[decoderIndex].m_blockCount < m_nbOriginalBlocks) // not enough blocks to decode -> store data
 | 
			
		||||
    {
 | 
			
		||||
        int blockIndex = superBlock->header.blockIndex;
 | 
			
		||||
        int blockCount = m_decoderSlots[decoderIndex].m_blockCount;
 | 
			
		||||
        int recoveryCount = m_decoderSlots[decoderIndex].m_recoveryCount;
 | 
			
		||||
        m_decoderSlots[decoderIndex].m_cm256DescriptorBlocks[blockCount].Index = blockIndex;
 | 
			
		||||
 | 
			
		||||
        if (blockIndex == 0) // first block with meta
 | 
			
		||||
        {
 | 
			
		||||
            m_decoderSlots[decoderIndex].m_metaRetrieved = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (blockIndex < m_nbOriginalBlocks) // original data
 | 
			
		||||
        {
 | 
			
		||||
            m_decoderSlots[decoderIndex].m_cm256DescriptorBlocks[blockCount].Block = (void *) storeOriginalBlock(decoderIndex, blockIndex, superBlock->protectedBlock);
 | 
			
		||||
            m_decoderSlots[decoderIndex].m_originalCount++;
 | 
			
		||||
        }
 | 
			
		||||
        else // recovery data
 | 
			
		||||
        {
 | 
			
		||||
            m_decoderSlots[decoderIndex].m_recoveryBlocks[recoveryCount] = superBlock->protectedBlock;
 | 
			
		||||
            m_decoderSlots[decoderIndex].m_cm256DescriptorBlocks[blockCount].Block = (void *) &m_decoderSlots[decoderIndex].m_recoveryBlocks[recoveryCount];
 | 
			
		||||
            m_decoderSlots[decoderIndex].m_recoveryCount++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    m_decoderSlots[decoderIndex].m_blockCount++;
 | 
			
		||||
 | 
			
		||||
    if (m_decoderSlots[decoderIndex].m_blockCount == m_nbOriginalBlocks) // ready to decode
 | 
			
		||||
    {
 | 
			
		||||
        m_decoderSlots[decoderIndex].m_decoded = true;
 | 
			
		||||
 | 
			
		||||
        if (m_cm256_OK && (m_decoderSlots[decoderIndex].m_recoveryCount > 0)) // recovery data used => need to decode FEC
 | 
			
		||||
        {
 | 
			
		||||
            m_paramsCM256.BlockBytes = sizeof(ProtectedBlock); // never changes
 | 
			
		||||
            m_paramsCM256.OriginalCount = m_nbOriginalBlocks;  // never changes
 | 
			
		||||
 | 
			
		||||
            if (m_decoderSlots[decoderIndex].m_metaRetrieved) {
 | 
			
		||||
                m_paramsCM256.RecoveryCount = m_currentMeta.m_nbFECBlocks;
 | 
			
		||||
            } else {
 | 
			
		||||
                m_paramsCM256.RecoveryCount = m_decoderSlots[decoderIndex].m_recoveryCount;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (m_cm256.cm256_decode(m_paramsCM256, m_decoderSlots[decoderIndex].m_cm256DescriptorBlocks)) // CM256 decode
 | 
			
		||||
            {
 | 
			
		||||
                qDebug() << "SDRdaemonFECBuffer::writeData: decode CM256 error:"
 | 
			
		||||
                        << " m_originalCount: " << m_decoderSlots[decoderIndex].m_originalCount
 | 
			
		||||
                        << " m_recoveryCount: " << m_decoderSlots[decoderIndex].m_recoveryCount;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                qDebug() << "SDRdaemonFECBuffer::writeData: decode CM256 success:"
 | 
			
		||||
                        << " m_originalCount: " << m_decoderSlots[decoderIndex].m_originalCount
 | 
			
		||||
                        << " m_recoveryCount: " << m_decoderSlots[decoderIndex].m_recoveryCount;
 | 
			
		||||
 | 
			
		||||
                for (int ir = 0; ir < m_decoderSlots[decoderIndex].m_recoveryCount; ir++) // restore missing blocks
 | 
			
		||||
                {
 | 
			
		||||
                    int recoveryIndex = m_nbOriginalBlocks - m_decoderSlots[decoderIndex].m_recoveryCount + ir;
 | 
			
		||||
                    int blockIndex = m_decoderSlots[decoderIndex].m_cm256DescriptorBlocks[recoveryIndex].Index;
 | 
			
		||||
                    ProtectedBlock *recoveredBlock = (ProtectedBlock *) m_decoderSlots[decoderIndex].m_cm256DescriptorBlocks[recoveryIndex].Block;
 | 
			
		||||
 | 
			
		||||
                    if (blockIndex == 0) // first block with meta
 | 
			
		||||
                    {
 | 
			
		||||
                        MetaDataFEC *metaData = (MetaDataFEC *) recoveredBlock;
 | 
			
		||||
 | 
			
		||||
                        boost::crc_32_type crc32;
 | 
			
		||||
                        crc32.process_bytes(metaData, 20);
 | 
			
		||||
 | 
			
		||||
                        if (crc32.checksum() == metaData->m_crc32)
 | 
			
		||||
                        {
 | 
			
		||||
                            m_decoderSlots[decoderIndex].m_metaRetrieved = true;
 | 
			
		||||
                            printMeta("SDRdaemonFECBuffer::writeData: recovered meta", metaData);
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            qDebug() << "SDRdaemonFECBuffer::writeData: recovered meta: invalid CRC32";
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    storeOriginalBlock(decoderIndex, blockIndex, *recoveredBlock);
 | 
			
		||||
 | 
			
		||||
                    qDebug() << "SDRdaemonFECBuffer::writeData: recovered block #" << blockIndex;
 | 
			
		||||
                } // restore missing blocks
 | 
			
		||||
            } // CM256 decode
 | 
			
		||||
        } // revovery
 | 
			
		||||
 | 
			
		||||
        if (m_decoderSlots[decoderIndex].m_metaRetrieved) // block zero with its meta data has been received
 | 
			
		||||
        {
 | 
			
		||||
            MetaDataFEC *metaData = getMetaData(decoderIndex);
 | 
			
		||||
 | 
			
		||||
            if (!(*metaData == m_currentMeta))
 | 
			
		||||
            {
 | 
			
		||||
                int sampleRate =  metaData->m_sampleRate;
 | 
			
		||||
 | 
			
		||||
                if (sampleRate > 0) {
 | 
			
		||||
                    m_bufferLenSec = (float) m_framesNbBytes / (float) (sampleRate * m_iqSampleSize);
 | 
			
		||||
                    m_balCorrLimit = sampleRate / 1000; // +/- 1 ms correction max per read
 | 
			
		||||
                    m_readNbBytes = (sampleRate * m_iqSampleSize) / 20;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                printMeta("SDRdaemonFECBuffer::writeData: new meta", metaData); // print for change other than timestamp
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            m_currentMeta = *metaData; // renew current meta
 | 
			
		||||
        } // check block 0
 | 
			
		||||
    } // decode
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t *SDRdaemonFECBuffer::readData(uint32_t length)
 | 
			
		||||
{
 | 
			
		||||
    uint8_t *buffer = (uint8_t *) m_frames;
 | 
			
		||||
    uint32_t readIndex = m_readIndex;
 | 
			
		||||
 | 
			
		||||
    m_nbReads++;
 | 
			
		||||
 | 
			
		||||
    // SEGFAULT FIX: arbitratily truncate so that it does not exceed buffer length
 | 
			
		||||
    if (length > framesSize) {
 | 
			
		||||
        length = framesSize;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (m_readIndex + length < m_framesNbBytes) // ends before buffer bound
 | 
			
		||||
    {
 | 
			
		||||
        m_readIndex += length;
 | 
			
		||||
        return &buffer[readIndex];
 | 
			
		||||
    }
 | 
			
		||||
    else if (m_readIndex + length == m_framesNbBytes) // ends at buffer bound
 | 
			
		||||
    {
 | 
			
		||||
        m_readIndex = 0;
 | 
			
		||||
        return &buffer[readIndex];
 | 
			
		||||
    }
 | 
			
		||||
    else // ends after buffer bound
 | 
			
		||||
    {
 | 
			
		||||
        if (length > m_readSize) // reallocate composition buffer if necessary
 | 
			
		||||
        {
 | 
			
		||||
            if (m_readBuffer) {
 | 
			
		||||
                delete[] m_readBuffer;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            m_readBuffer = new uint8_t[length];
 | 
			
		||||
            m_readSize = length;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        std::memcpy((void *) m_readBuffer, (const void *) &buffer[m_readIndex], m_framesNbBytes - m_readIndex); // copy end of buffer
 | 
			
		||||
        length -= m_framesNbBytes - m_readIndex;
 | 
			
		||||
        std::memcpy((void *) &m_readBuffer[m_framesNbBytes - m_readIndex], (const void *) buffer, length); // copy start of buffer
 | 
			
		||||
        m_readIndex = length;
 | 
			
		||||
        return m_readBuffer;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SDRdaemonFECBuffer::printMeta(const QString& header, MetaDataFEC *metaData)
 | 
			
		||||
{
 | 
			
		||||
	qDebug() << header << ": "
 | 
			
		||||
            << "|" << metaData->m_centerFrequency
 | 
			
		||||
            << ":" << metaData->m_sampleRate
 | 
			
		||||
            << ":" << (int) (metaData->m_sampleBytes & 0xF)
 | 
			
		||||
            << ":" << (int) metaData->m_sampleBits
 | 
			
		||||
            << ":" << (int) metaData->m_nbOriginalBlocks
 | 
			
		||||
            << ":" << (int) metaData->m_nbFECBlocks
 | 
			
		||||
            << "|" << metaData->m_tv_sec
 | 
			
		||||
            << ":" << metaData->m_tv_usec
 | 
			
		||||
            << "|";
 | 
			
		||||
}
 | 
			
		||||
@ -1,272 +0,0 @@
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Copyright (C) 2016 Edouard Griffiths, F4EXB                                   //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// This program is free software; you can redistribute it and/or modify          //
 | 
			
		||||
// it under the terms of the GNU General Public License as published by          //
 | 
			
		||||
// the Free Software Foundation as version 3 of the License, or                  //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// This program is distributed in the hope that it will be useful,               //
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | 
			
		||||
// GNU General Public License V3 for more details.                               //
 | 
			
		||||
//                                                                               //
 | 
			
		||||
// You should have received a copy of the GNU General Public License             //
 | 
			
		||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
#ifndef DEVICES_SDRDAEMON_SDRDAEMONFECBUFFER_H_
 | 
			
		||||
#define DEVICES_SDRDAEMON_SDRDAEMONFECBUFFER_H_
 | 
			
		||||
 | 
			
		||||
#include <QString>
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include "cm256.h"
 | 
			
		||||
#include "util/movingaverage.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define SDRDAEMONFEC_UDPSIZE 512               // UDP payload size
 | 
			
		||||
#define SDRDAEMONSOURCE_NBORIGINALBLOCKS 128      // number of sample blocks per frame excluding FEC blocks
 | 
			
		||||
#define SDRDAEMONFEC_NBDECODERSLOTS 16         // power of two sub multiple of uint16_t size. A too large one is superfluous.
 | 
			
		||||
 | 
			
		||||
class SDRdaemonFECBuffer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
#pragma pack(push, 1)
 | 
			
		||||
    struct MetaDataFEC
 | 
			
		||||
    {
 | 
			
		||||
        uint32_t m_centerFrequency;   //!<  4 center frequency in kHz
 | 
			
		||||
        uint32_t m_sampleRate;        //!<  8 sample rate in Hz
 | 
			
		||||
        uint8_t  m_sampleBytes;       //!<  9 MSB(4): indicators, LSB(4) number of bytes per sample
 | 
			
		||||
        uint8_t  m_sampleBits;        //!< 10 number of effective bits per sample
 | 
			
		||||
        uint8_t  m_nbOriginalBlocks;  //!< 11 number of blocks with original (protected) data
 | 
			
		||||
        uint8_t  m_nbFECBlocks;       //!< 12 number of blocks carrying FEC
 | 
			
		||||
        uint32_t m_tv_sec;            //!< 16 seconds of timestamp at start time of super-frame processing
 | 
			
		||||
        uint32_t m_tv_usec;           //!< 20 microseconds of timestamp at start time of super-frame processing
 | 
			
		||||
        uint32_t m_crc32;             //!< 24 CRC32 of the above
 | 
			
		||||
 | 
			
		||||
        bool operator==(const MetaDataFEC& rhs)
 | 
			
		||||
        {
 | 
			
		||||
            return (memcmp((const void *) this, (const void *) &rhs, 12) == 0); // Only the 12 first bytes are relevant
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void init()
 | 
			
		||||
        {
 | 
			
		||||
            memset((void *) this, 0, sizeof(MetaDataFEC));
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct Sample
 | 
			
		||||
    {
 | 
			
		||||
        int16_t i;
 | 
			
		||||
        int16_t q;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct Header
 | 
			
		||||
    {
 | 
			
		||||
        uint16_t frameIndex;
 | 
			
		||||
        uint8_t  blockIndex;
 | 
			
		||||
        uint8_t  filler;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    static const int samplesPerBlock = (SDRDAEMONFEC_UDPSIZE - sizeof(Header)) / sizeof(Sample);
 | 
			
		||||
    static const int framesSize = SDRDAEMONFEC_NBDECODERSLOTS * (SDRDAEMONSOURCE_NBORIGINALBLOCKS - 1) * (SDRDAEMONFEC_UDPSIZE - sizeof(Header));
 | 
			
		||||
 | 
			
		||||
    struct ProtectedBlock
 | 
			
		||||
    {
 | 
			
		||||
        Sample samples[samplesPerBlock];
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct SuperBlock
 | 
			
		||||
    {
 | 
			
		||||
        Header         header;
 | 
			
		||||
        ProtectedBlock protectedBlock;
 | 
			
		||||
    };
 | 
			
		||||
#pragma pack(pop)
 | 
			
		||||
 | 
			
		||||
	SDRdaemonFECBuffer(uint32_t throttlems);
 | 
			
		||||
	~SDRdaemonFECBuffer();
 | 
			
		||||
 | 
			
		||||
	// R/W operations
 | 
			
		||||
	void writeData(char *array);        //!< Write data into buffer.
 | 
			
		||||
	uint8_t *readData(uint32_t length); //!< Read data from buffer
 | 
			
		||||
 | 
			
		||||
	// meta data
 | 
			
		||||
	const MetaDataFEC& getCurrentMeta() const { return m_currentMeta; }
 | 
			
		||||
 | 
			
		||||
	// samples timestamp
 | 
			
		||||
	uint32_t getTVOutSec() const { return m_tvOut_sec; }
 | 
			
		||||
	uint32_t getTVOutUsec() const { return m_tvOut_usec; }
 | 
			
		||||
 | 
			
		||||
    // stats
 | 
			
		||||
 | 
			
		||||
	int getCurNbBlocks() const { return m_curNbBlocks; }
 | 
			
		||||
    int getCurOriginalBlocks() const { return m_curOriginalBlocks; }
 | 
			
		||||
    int getCurNbRecovery() const { return m_curNbRecovery; }
 | 
			
		||||
    float getAvgNbBlocks() const { return m_avgNbBlocks; }
 | 
			
		||||
    float getAvgOriginalBlocks() const { return m_avgOrigBlocks; }
 | 
			
		||||
    float getAvgNbRecovery() const { return m_avgNbRecovery; }
 | 
			
		||||
 | 
			
		||||
    int getMinNbBlocks()
 | 
			
		||||
    {
 | 
			
		||||
        int minNbBlocks = m_minNbBlocks;
 | 
			
		||||
        m_minNbBlocks = 256;
 | 
			
		||||
        return minNbBlocks;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int getMinOriginalBlocks()
 | 
			
		||||
    {
 | 
			
		||||
        int minOriginalBlocks = m_minOriginalBlocks;
 | 
			
		||||
        m_minOriginalBlocks = 128;
 | 
			
		||||
        return minOriginalBlocks;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int getMaxNbRecovery()
 | 
			
		||||
    {
 | 
			
		||||
        int maxNbRecovery = m_maxNbRecovery;
 | 
			
		||||
        m_maxNbRecovery = 0;
 | 
			
		||||
        return maxNbRecovery;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool allFramesDecoded()
 | 
			
		||||
    {
 | 
			
		||||
        bool framesDecoded = m_framesDecoded;
 | 
			
		||||
        m_framesDecoded = true;
 | 
			
		||||
        return framesDecoded;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    float getBufferLengthInSecs() const { return m_bufferLenSec; }
 | 
			
		||||
    int32_t getRWBalanceCorrection() const { return m_balCorrection; }
 | 
			
		||||
 | 
			
		||||
    /** Get buffer gauge value in % of buffer size ([-50:50])
 | 
			
		||||
     *  [-50:0] : write leads or read lags
 | 
			
		||||
     *  [0:50]  : read leads or write lags
 | 
			
		||||
     */
 | 
			
		||||
    inline int32_t getBufferGauge() const
 | 
			
		||||
    {
 | 
			
		||||
        if (m_framesNbBytes)
 | 
			
		||||
        {
 | 
			
		||||
            int32_t val = (m_wrDeltaEstimate * 100) / (int32_t) m_framesNbBytes;
 | 
			
		||||
            int32_t ret = val < 0 ? -val - 50 : 50 -val;
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            return 0; // default position
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static const int m_udpPayloadSize = SDRDAEMONFEC_UDPSIZE;
 | 
			
		||||
    static const int m_nbOriginalBlocks = SDRDAEMONSOURCE_NBORIGINALBLOCKS;
 | 
			
		||||
	static const int m_sampleSize;
 | 
			
		||||
	static const int m_iqSampleSize;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static const int nbDecoderSlots = SDRDAEMONFEC_NBDECODERSLOTS;
 | 
			
		||||
 | 
			
		||||
#pragma pack(push, 1)
 | 
			
		||||
    struct BufferFrame
 | 
			
		||||
    {
 | 
			
		||||
        ProtectedBlock  m_blocks[m_nbOriginalBlocks - 1];
 | 
			
		||||
    };
 | 
			
		||||
#pragma pack(pop)
 | 
			
		||||
 | 
			
		||||
    struct DecoderSlot
 | 
			
		||||
    {
 | 
			
		||||
        ProtectedBlock       m_blockZero;                                 //!< First block of a frame. Has meta data.
 | 
			
		||||
        ProtectedBlock       m_originalBlocks[m_nbOriginalBlocks];        //!< Original blocks retrieved directly or by later FEC
 | 
			
		||||
        ProtectedBlock       m_recoveryBlocks[m_nbOriginalBlocks];        //!< Recovery blocks (FEC blocks) with max size
 | 
			
		||||
        CM256::cm256_block   m_cm256DescriptorBlocks[m_nbOriginalBlocks]; //!< CM256 decoder descriptors (block addresses and block indexes)
 | 
			
		||||
        int                  m_blockCount;         //!< number of blocks received for this frame
 | 
			
		||||
        int                  m_originalCount;      //!< number of original blocks received
 | 
			
		||||
        int                  m_recoveryCount;      //!< number of recovery blocks received
 | 
			
		||||
        bool                 m_decoded;            //!< true if decoded
 | 
			
		||||
        bool                 m_metaRetrieved;      //!< true if meta data (block zero) was retrieved
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MetaDataFEC          m_currentMeta;          //!< Stored current meta data
 | 
			
		||||
    CM256::cm256_encoder_params m_paramsCM256;          //!< CM256 decoder parameters block
 | 
			
		||||
    DecoderSlot          m_decoderSlots[nbDecoderSlots]; //!< CM256 decoding control/buffer slots
 | 
			
		||||
    BufferFrame          m_frames[nbDecoderSlots];       //!< Samples buffer
 | 
			
		||||
    uint32_t             m_framesNbBytes;                //!< Number of bytes in samples buffer
 | 
			
		||||
    int                  m_decoderIndexHead;     //!< index of the current head frame slot in decoding slots
 | 
			
		||||
    int                  m_frameHead;            //!< index of the current head frame sent
 | 
			
		||||
    int                  m_curNbBlocks;          //!< (stats) instantaneous number of blocks received
 | 
			
		||||
    int                  m_minNbBlocks;          //!< (stats) minimum number of blocks received since last poll
 | 
			
		||||
    int                  m_curOriginalBlocks;    //!< (stats) instantanous number of original blocks received
 | 
			
		||||
    int                  m_minOriginalBlocks;    //!< (stats) minimum number of original blocks received since last poll
 | 
			
		||||
    int                  m_curNbRecovery;        //!< (stats) instantaneous number of recovery blocks used
 | 
			
		||||
    int                  m_maxNbRecovery;        //!< (stats) maximum number of recovery blocks used since last poll
 | 
			
		||||
    MovingAverage<int, int, 10> m_avgNbBlocks;   //!< (stats) average number of blocks received
 | 
			
		||||
    MovingAverage<int, int, 10> m_avgOrigBlocks; //!< (stats) average number of original blocks received
 | 
			
		||||
    MovingAverage<int, int, 10> m_avgNbRecovery; //!< (stats) average number of recovery blocks used
 | 
			
		||||
    bool                 m_framesDecoded;        //!< [stats] true if all frames were decoded since last poll
 | 
			
		||||
    int                  m_readIndex;            //!< current byte read index in frames buffer
 | 
			
		||||
    int                  m_wrDeltaEstimate;      //!< Sampled estimate of write to read indexes difference
 | 
			
		||||
    uint32_t             m_tvOut_sec;            //!< Estimated returned samples timestamp (seconds)
 | 
			
		||||
    uint32_t             m_tvOut_usec;           //!< Estimated returned samples timestamp (microseconds)
 | 
			
		||||
    int                  m_readNbBytes;          //!< Nominal number of bytes per read (50ms)
 | 
			
		||||
 | 
			
		||||
	uint32_t m_throttlemsNominal;  //!< Initial throttle in ms
 | 
			
		||||
    uint8_t* m_readBuffer;         //!< Read buffer to hold samples when looping back to beginning of raw buffer
 | 
			
		||||
    uint32_t m_readSize;           //!< Read buffer size
 | 
			
		||||
 | 
			
		||||
    float    m_bufferLenSec;
 | 
			
		||||
 | 
			
		||||
    int      m_nbReads;       //!< Number of buffer reads since start of auto R/W balance correction period
 | 
			
		||||
    int      m_nbWrites;      //!< Number of buffer writes since start of auto R/W balance correction period
 | 
			
		||||
    int      m_balCorrection; //!< R/W balance correction in number of samples
 | 
			
		||||
    int      m_balCorrLimit;  //!< Correction absolute value limit in number of samples
 | 
			
		||||
    CM256    m_cm256;         //!< CM256 library
 | 
			
		||||
    bool     m_cm256_OK;      //!< CM256 library initialized OK
 | 
			
		||||
 | 
			
		||||
    inline ProtectedBlock* storeOriginalBlock(int slotIndex, int blockIndex, const ProtectedBlock& protectedBlock)
 | 
			
		||||
    {
 | 
			
		||||
        if (blockIndex == 0) {
 | 
			
		||||
            // m_decoderSlots[slotIndex].m_originalBlocks[0] = protectedBlock;
 | 
			
		||||
            // return &m_decoderSlots[slotIndex].m_originalBlocks[0];
 | 
			
		||||
            m_decoderSlots[slotIndex].m_blockZero = protectedBlock;
 | 
			
		||||
            return &m_decoderSlots[slotIndex].m_blockZero;
 | 
			
		||||
        } else {
 | 
			
		||||
            // m_decoderSlots[slotIndex].m_originalBlocks[blockIndex] = protectedBlock;
 | 
			
		||||
            // return &m_decoderSlots[slotIndex].m_originalBlocks[blockIndex];
 | 
			
		||||
            m_frames[slotIndex].m_blocks[blockIndex - 1] = protectedBlock;
 | 
			
		||||
            return &m_frames[slotIndex].m_blocks[blockIndex - 1];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline ProtectedBlock& getOriginalBlock(int slotIndex, int blockIndex)
 | 
			
		||||
    {
 | 
			
		||||
        if (blockIndex == 0) {
 | 
			
		||||
            // return m_decoderSlots[slotIndex].m_originalBlocks[0];
 | 
			
		||||
            return m_decoderSlots[slotIndex].m_blockZero;
 | 
			
		||||
        } else {
 | 
			
		||||
            // return m_decoderSlots[slotIndex].m_originalBlocks[blockIndex];
 | 
			
		||||
            return m_frames[slotIndex].m_blocks[blockIndex - 1];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline MetaDataFEC *getMetaData(int slotIndex)
 | 
			
		||||
    {
 | 
			
		||||
        // return (MetaDataFEC *) &m_decoderSlots[slotIndex].m_originalBlocks[0];
 | 
			
		||||
        return (MetaDataFEC *) &m_decoderSlots[slotIndex].m_blockZero;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline void resetOriginalBlocks(int slotIndex)
 | 
			
		||||
    {
 | 
			
		||||
        // memset((void *) m_decoderSlots[slotIndex].m_originalBlocks, 0, m_nbOriginalBlocks * sizeof(ProtectedBlock));
 | 
			
		||||
        memset((void *) &m_decoderSlots[slotIndex].m_blockZero, 0, sizeof(ProtectedBlock));
 | 
			
		||||
        memset((void *) m_frames[slotIndex].m_blocks, 0, (m_nbOriginalBlocks - 1) * sizeof(ProtectedBlock));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void initDecodeAllSlots();
 | 
			
		||||
    void initReadIndex();
 | 
			
		||||
    void rwCorrectionEstimate(int slotIndex);
 | 
			
		||||
    void checkSlotData(int slotIndex);
 | 
			
		||||
    void initDecodeSlot(int slotIndex);
 | 
			
		||||
 | 
			
		||||
    static void printMeta(const QString& header, MetaDataFEC *metaData);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif /* DEVICES_SDRDAEMON_SDRDAEMONFECBUFFER_H_ */
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user