2016-06-19 03:56:49 -04:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// 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>
|
2018-02-24 04:29:27 -05:00
|
|
|
#include <algorithm>
|
2016-07-24 13:50:51 -04:00
|
|
|
#include <boost/crc.hpp>
|
|
|
|
#include <boost/cstdint.hpp>
|
2017-06-09 07:58:27 -04:00
|
|
|
#include "sdrdaemonsourcebuffer.h"
|
2016-07-24 13:50:51 -04:00
|
|
|
|
2016-06-19 03:56:49 -04:00
|
|
|
|
|
|
|
|
2018-03-03 19:47:51 -05:00
|
|
|
SDRdaemonSourceBuffer::SDRdaemonSourceBuffer() :
|
2016-07-05 18:43:38 -04:00
|
|
|
m_decoderIndexHead(nbDecoderSlots/2),
|
2017-05-25 14:13:34 -04:00
|
|
|
m_frameHead(0),
|
2016-06-19 18:45:24 -04:00
|
|
|
m_curNbBlocks(0),
|
2016-07-17 18:39:35 -04:00
|
|
|
m_minNbBlocks(256),
|
2017-05-25 14:13:34 -04:00
|
|
|
m_curOriginalBlocks(0),
|
2016-07-27 12:49:17 -04:00
|
|
|
m_minOriginalBlocks(128),
|
2016-06-19 18:45:24 -04:00
|
|
|
m_curNbRecovery(0),
|
2016-07-17 18:39:35 -04:00
|
|
|
m_maxNbRecovery(0),
|
|
|
|
m_framesDecoded(true),
|
2016-06-19 18:45:24 -04:00
|
|
|
m_readIndex(0),
|
|
|
|
m_readBuffer(0),
|
|
|
|
m_readSize(0),
|
2016-07-12 21:31:19 -04:00
|
|
|
m_bufferLenSec(0.0f),
|
2017-05-25 14:13:34 -04:00
|
|
|
m_nbReads(0),
|
|
|
|
m_nbWrites(0),
|
|
|
|
m_balCorrection(0),
|
|
|
|
m_balCorrLimit(0)
|
2016-06-19 03:56:49 -04:00
|
|
|
{
|
|
|
|
m_currentMeta.init();
|
2016-06-21 15:49:27 -04:00
|
|
|
m_framesNbBytes = nbDecoderSlots * sizeof(BufferFrame);
|
2016-06-19 18:45:24 -04:00
|
|
|
m_wrDeltaEstimate = m_framesNbBytes / 2;
|
2016-07-24 06:53:39 -04:00
|
|
|
m_tvOut_sec = 0;
|
|
|
|
m_tvOut_usec = 0;
|
2016-07-12 21:31:19 -04:00
|
|
|
m_readNbBytes = 1;
|
2016-06-22 19:31:40 -04:00
|
|
|
m_paramsCM256.BlockBytes = sizeof(ProtectedBlock); // never changes
|
|
|
|
m_paramsCM256.OriginalCount = m_nbOriginalBlocks; // never changes
|
2016-07-17 17:33:50 -04:00
|
|
|
|
2016-07-23 13:59:42 -04:00
|
|
|
if (!m_cm256.isInitialized()) {
|
2016-07-17 17:33:50 -04:00
|
|
|
m_cm256_OK = false;
|
2017-06-09 08:18:11 -04:00
|
|
|
qDebug() << "SDRdaemonSourceBuffer::SDRdaemonSourceBuffer: cannot initialize CM256 library";
|
2016-07-17 17:33:50 -04:00
|
|
|
} else {
|
|
|
|
m_cm256_OK = true;
|
|
|
|
}
|
2018-02-24 04:29:27 -05:00
|
|
|
|
|
|
|
std::fill(m_decoderSlots, m_decoderSlots + nbDecoderSlots, DecoderSlot());
|
|
|
|
std::fill(m_frames, m_frames + nbDecoderSlots, BufferFrame());
|
2016-06-19 03:56:49 -04:00
|
|
|
}
|
|
|
|
|
2017-06-09 08:14:32 -04:00
|
|
|
SDRdaemonSourceBuffer::~SDRdaemonSourceBuffer()
|
2016-06-19 03:56:49 -04:00
|
|
|
{
|
|
|
|
if (m_readBuffer) {
|
|
|
|
delete[] m_readBuffer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-09 08:14:32 -04:00
|
|
|
void SDRdaemonSourceBuffer::initDecodeAllSlots()
|
2016-06-19 03:56:49 -04:00
|
|
|
{
|
2016-06-19 18:45:24 -04:00
|
|
|
for (int i = 0; i < nbDecoderSlots; i++)
|
|
|
|
{
|
|
|
|
m_decoderSlots[i].m_blockCount = 0;
|
2016-07-06 21:49:47 -04:00
|
|
|
m_decoderSlots[i].m_originalCount = 0;
|
2016-06-19 18:45:24 -04:00
|
|
|
m_decoderSlots[i].m_recoveryCount = 0;
|
|
|
|
m_decoderSlots[i].m_decoded = false;
|
2016-06-22 18:58:07 -04:00
|
|
|
m_decoderSlots[i].m_metaRetrieved = false;
|
2016-07-28 11:09:15 -04:00
|
|
|
resetOriginalBlocks(i);
|
2016-07-17 17:33:50 -04:00
|
|
|
memset((void *) m_decoderSlots[i].m_recoveryBlocks, 0, m_nbOriginalBlocks * sizeof(ProtectedBlock));
|
2016-06-19 18:45:24 -04:00
|
|
|
}
|
2016-06-19 03:56:49 -04:00
|
|
|
}
|
|
|
|
|
2017-06-09 08:14:32 -04:00
|
|
|
void SDRdaemonSourceBuffer::initDecodeSlot(int slotIndex)
|
2016-07-17 17:33:50 -04:00
|
|
|
{
|
|
|
|
// collect stats before voiding the slot
|
2016-07-17 18:39:35 -04:00
|
|
|
|
2016-07-17 17:33:50 -04:00
|
|
|
m_curNbBlocks = m_decoderSlots[slotIndex].m_blockCount;
|
2016-07-27 12:49:17 -04:00
|
|
|
m_curOriginalBlocks = m_decoderSlots[slotIndex].m_originalCount;
|
2016-07-17 17:33:50 -04:00
|
|
|
m_curNbRecovery = m_decoderSlots[slotIndex].m_recoveryCount;
|
|
|
|
m_avgNbBlocks(m_curNbBlocks);
|
2016-07-27 12:49:17 -04:00
|
|
|
m_avgOrigBlocks(m_curOriginalBlocks);
|
2016-07-17 17:33:50 -04:00
|
|
|
m_avgNbRecovery(m_curNbRecovery);
|
2016-07-17 18:39:35 -04:00
|
|
|
m_framesDecoded = m_framesDecoded && m_decoderSlots[slotIndex].m_decoded;
|
|
|
|
|
|
|
|
if (m_curNbBlocks < m_minNbBlocks) {
|
|
|
|
m_minNbBlocks = m_curNbBlocks;
|
|
|
|
}
|
|
|
|
|
2016-07-27 12:49:17 -04:00
|
|
|
if (m_curOriginalBlocks < m_minOriginalBlocks) {
|
|
|
|
m_minOriginalBlocks = m_curOriginalBlocks;
|
|
|
|
}
|
|
|
|
|
2016-07-17 18:39:35 -04:00
|
|
|
if (m_curNbRecovery > m_maxNbRecovery) {
|
|
|
|
m_maxNbRecovery = m_curNbRecovery;
|
|
|
|
}
|
|
|
|
|
2016-07-17 17:33:50 -04:00
|
|
|
// void the slot
|
2016-07-17 18:39:35 -04:00
|
|
|
|
2016-07-17 17:33:50 -04:00
|
|
|
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;
|
2016-07-28 11:09:15 -04:00
|
|
|
|
|
|
|
resetOriginalBlocks(slotIndex);
|
2016-07-17 17:33:50 -04:00
|
|
|
memset((void *) m_decoderSlots[slotIndex].m_recoveryBlocks, 0, m_nbOriginalBlocks * sizeof(ProtectedBlock));
|
|
|
|
}
|
|
|
|
|
2017-06-09 08:14:32 -04:00
|
|
|
void SDRdaemonSourceBuffer::initReadIndex()
|
2016-06-19 03:56:49 -04:00
|
|
|
{
|
2016-07-05 18:43:38 -04:00
|
|
|
m_readIndex = ((m_decoderIndexHead + (nbDecoderSlots/2)) % nbDecoderSlots) * sizeof(BufferFrame);
|
2016-06-19 18:45:24 -04:00
|
|
|
m_wrDeltaEstimate = m_framesNbBytes / 2;
|
2016-07-12 21:31:19 -04:00
|
|
|
m_nbReads = 0;
|
|
|
|
m_nbWrites = 0;
|
|
|
|
}
|
|
|
|
|
2017-06-09 08:14:32 -04:00
|
|
|
void SDRdaemonSourceBuffer::rwCorrectionEstimate(int slotIndex)
|
2016-07-12 21:31:19 -04:00
|
|
|
{
|
|
|
|
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
|
|
|
|
int 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));
|
|
|
|
|
2017-05-25 14:13:34 -04:00
|
|
|
if (normalizedReadIndex < (nbDecoderSlots/ 2) * (int) sizeof(BufferFrame)) // read leads
|
2016-07-12 21:31:19 -04:00
|
|
|
{
|
|
|
|
dBytes = - normalizedReadIndex - rwDelta;
|
|
|
|
}
|
|
|
|
else // read lags
|
|
|
|
{
|
|
|
|
dBytes = (nbDecoderSlots * sizeof(BufferFrame)) - normalizedReadIndex - rwDelta;
|
|
|
|
}
|
|
|
|
|
2018-09-09 15:26:47 -04:00
|
|
|
m_balCorrection = (m_balCorrection / 4) + (dBytes / (int) (m_currentMeta.m_sampleBytes * 2 * m_nbReads)); // correction is in number of samples. Alpha = 0.25
|
2016-07-12 21:31:19 -04:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2016-06-19 03:56:49 -04:00
|
|
|
}
|
|
|
|
|
2017-06-09 08:14:32 -04:00
|
|
|
void SDRdaemonSourceBuffer::checkSlotData(int slotIndex)
|
2016-07-05 20:54:01 -04:00
|
|
|
{
|
2016-07-12 02:52:38 -04:00
|
|
|
int pseudoWriteIndex = slotIndex * sizeof(BufferFrame);
|
|
|
|
m_wrDeltaEstimate = pseudoWriteIndex - m_readIndex;
|
2016-07-12 21:31:19 -04:00
|
|
|
m_nbWrites++;
|
2016-07-12 02:52:38 -04:00
|
|
|
|
2016-07-24 06:53:39 -04:00
|
|
|
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;
|
2018-09-09 16:35:25 -04:00
|
|
|
ts -= (rwDelayBytes * 1000000LL) / (sampleRate * 2 * m_currentMeta.m_sampleBytes);
|
2016-07-24 06:53:39 -04:00
|
|
|
m_tvOut_sec = ts / 1000000LL;
|
|
|
|
m_tvOut_usec = ts - (m_tvOut_sec * 1000000LL);
|
|
|
|
}
|
|
|
|
|
2016-07-05 20:54:01 -04:00
|
|
|
if (!m_decoderSlots[slotIndex].m_decoded)
|
|
|
|
{
|
2017-06-09 08:18:11 -04:00
|
|
|
qDebug() << "SDRdaemonSourceBuffer::checkSlotData: incomplete frame:"
|
2016-07-05 20:54:01 -04:00
|
|
|
<< " m_blockCount: " << m_decoderSlots[slotIndex].m_blockCount
|
|
|
|
<< " m_recoveryCount: " << m_decoderSlots[slotIndex].m_recoveryCount;
|
|
|
|
}
|
2016-06-19 18:45:24 -04:00
|
|
|
}
|
2016-06-19 03:56:49 -04:00
|
|
|
|
2017-06-09 08:14:32 -04:00
|
|
|
void SDRdaemonSourceBuffer::writeData(char *array)
|
2016-06-19 18:45:24 -04:00
|
|
|
{
|
2016-07-06 20:36:44 -04:00
|
|
|
SuperBlock *superBlock = (SuperBlock *) array;
|
|
|
|
int frameIndex = superBlock->header.frameIndex;
|
|
|
|
int decoderIndex = frameIndex % nbDecoderSlots;
|
|
|
|
|
2016-07-17 17:33:50 -04:00
|
|
|
// frame break
|
|
|
|
|
2016-07-06 20:36:44 -04:00
|
|
|
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
|
|
|
|
{
|
2016-07-17 17:33:50 -04:00
|
|
|
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
|
2016-07-15 13:44:02 -04:00
|
|
|
}
|
2016-07-06 20:36:44 -04:00
|
|
|
|
2016-07-17 17:33:50 -04:00
|
|
|
// Block processing
|
|
|
|
|
2016-07-06 21:49:47 -04:00
|
|
|
if (m_decoderSlots[decoderIndex].m_blockCount < m_nbOriginalBlocks) // not enough blocks to decode -> store data
|
2016-07-06 20:36:44 -04:00
|
|
|
{
|
2016-07-17 17:33:50 -04:00
|
|
|
int blockIndex = superBlock->header.blockIndex;
|
2016-07-06 21:49:47 -04:00
|
|
|
int blockCount = m_decoderSlots[decoderIndex].m_blockCount;
|
|
|
|
int recoveryCount = m_decoderSlots[decoderIndex].m_recoveryCount;
|
2016-07-06 20:36:44 -04:00
|
|
|
m_decoderSlots[decoderIndex].m_cm256DescriptorBlocks[blockCount].Index = blockIndex;
|
|
|
|
|
|
|
|
if (blockIndex == 0) // first block with meta
|
|
|
|
{
|
|
|
|
m_decoderSlots[decoderIndex].m_metaRetrieved = true;
|
|
|
|
}
|
2016-07-17 17:33:50 -04:00
|
|
|
|
|
|
|
if (blockIndex < m_nbOriginalBlocks) // original data
|
2016-07-06 20:36:44 -04:00
|
|
|
{
|
2016-07-28 11:09:15 -04:00
|
|
|
m_decoderSlots[decoderIndex].m_cm256DescriptorBlocks[blockCount].Block = (void *) storeOriginalBlock(decoderIndex, blockIndex, superBlock->protectedBlock);
|
2016-07-06 21:49:47 -04:00
|
|
|
m_decoderSlots[decoderIndex].m_originalCount++;
|
2016-07-06 20:36:44 -04:00
|
|
|
}
|
|
|
|
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++;
|
|
|
|
}
|
|
|
|
}
|
2016-07-06 21:49:47 -04:00
|
|
|
|
2016-07-15 13:44:02 -04:00
|
|
|
m_decoderSlots[decoderIndex].m_blockCount++;
|
|
|
|
|
2016-07-06 21:49:47 -04:00
|
|
|
if (m_decoderSlots[decoderIndex].m_blockCount == m_nbOriginalBlocks) // ready to decode
|
2016-07-06 20:36:44 -04:00
|
|
|
{
|
2016-07-06 21:49:47 -04:00
|
|
|
m_decoderSlots[decoderIndex].m_decoded = true;
|
|
|
|
|
2016-07-17 17:33:50 -04:00
|
|
|
if (m_cm256_OK && (m_decoderSlots[decoderIndex].m_recoveryCount > 0)) // recovery data used => need to decode FEC
|
2016-07-15 13:44:02 -04:00
|
|
|
{
|
2016-07-17 17:33:50 -04:00
|
|
|
m_paramsCM256.BlockBytes = sizeof(ProtectedBlock); // never changes
|
|
|
|
m_paramsCM256.OriginalCount = m_nbOriginalBlocks; // never changes
|
2016-07-15 13:44:02 -04:00
|
|
|
|
2016-07-17 17:33:50 -04:00
|
|
|
if (m_decoderSlots[decoderIndex].m_metaRetrieved) {
|
|
|
|
m_paramsCM256.RecoveryCount = m_currentMeta.m_nbFECBlocks;
|
|
|
|
} else {
|
|
|
|
m_paramsCM256.RecoveryCount = m_decoderSlots[decoderIndex].m_recoveryCount;
|
|
|
|
}
|
2016-07-06 20:36:44 -04:00
|
|
|
|
2016-07-23 13:59:42 -04:00
|
|
|
if (m_cm256.cm256_decode(m_paramsCM256, m_decoderSlots[decoderIndex].m_cm256DescriptorBlocks)) // CM256 decode
|
2016-07-06 20:36:44 -04:00
|
|
|
{
|
2017-06-09 08:18:11 -04:00
|
|
|
qDebug() << "SDRdaemonSourceBuffer::writeData: decode CM256 error:"
|
2016-07-06 21:49:47 -04:00
|
|
|
<< " m_originalCount: " << m_decoderSlots[decoderIndex].m_originalCount
|
2016-07-06 20:36:44 -04:00
|
|
|
<< " m_recoveryCount: " << m_decoderSlots[decoderIndex].m_recoveryCount;
|
|
|
|
}
|
2016-07-17 17:33:50 -04:00
|
|
|
else
|
2016-07-06 20:36:44 -04:00
|
|
|
{
|
2017-06-09 08:18:11 -04:00
|
|
|
qDebug() << "SDRdaemonSourceBuffer::writeData: decode CM256 success:"
|
2016-07-06 21:49:47 -04:00
|
|
|
<< " m_originalCount: " << m_decoderSlots[decoderIndex].m_originalCount
|
2016-07-06 20:36:44 -04:00
|
|
|
<< " m_recoveryCount: " << m_decoderSlots[decoderIndex].m_recoveryCount;
|
|
|
|
|
2016-07-17 17:33:50 -04:00
|
|
|
for (int ir = 0; ir < m_decoderSlots[decoderIndex].m_recoveryCount; ir++) // restore missing blocks
|
2016-07-06 20:36:44 -04:00
|
|
|
{
|
2016-07-17 17:33:50 -04:00
|
|
|
int recoveryIndex = m_nbOriginalBlocks - m_decoderSlots[decoderIndex].m_recoveryCount + ir;
|
|
|
|
int blockIndex = m_decoderSlots[decoderIndex].m_cm256DescriptorBlocks[recoveryIndex].Index;
|
2016-07-23 17:14:22 -04:00
|
|
|
ProtectedBlock *recoveredBlock = (ProtectedBlock *) m_decoderSlots[decoderIndex].m_cm256DescriptorBlocks[recoveryIndex].Block;
|
2016-07-06 20:36:44 -04:00
|
|
|
|
2016-07-17 17:33:50 -04:00
|
|
|
if (blockIndex == 0) // first block with meta
|
2016-07-06 20:36:44 -04:00
|
|
|
{
|
2016-07-24 13:50:51 -04:00
|
|
|
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;
|
2017-06-09 08:18:11 -04:00
|
|
|
printMeta("SDRdaemonSourceBuffer::writeData: recovered meta", metaData);
|
2016-07-24 13:50:51 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-06-09 08:18:11 -04:00
|
|
|
qDebug() << "SDRdaemonSourceBuffer::writeData: recovered meta: invalid CRC32";
|
2016-07-24 13:50:51 -04:00
|
|
|
}
|
2016-07-06 20:36:44 -04:00
|
|
|
}
|
|
|
|
|
2016-07-28 11:09:15 -04:00
|
|
|
storeOriginalBlock(decoderIndex, blockIndex, *recoveredBlock);
|
2016-07-20 02:54:31 -04:00
|
|
|
|
2017-06-09 08:18:11 -04:00
|
|
|
qDebug() << "SDRdaemonSourceBuffer::writeData: recovered block #" << blockIndex;
|
2016-07-17 17:33:50 -04:00
|
|
|
} // restore missing blocks
|
|
|
|
} // CM256 decode
|
2016-07-06 21:49:47 -04:00
|
|
|
} // revovery
|
2016-07-06 20:36:44 -04:00
|
|
|
|
2016-07-17 17:33:50 -04:00
|
|
|
if (m_decoderSlots[decoderIndex].m_metaRetrieved) // block zero with its meta data has been received
|
|
|
|
{
|
2016-07-28 11:09:15 -04:00
|
|
|
MetaDataFEC *metaData = getMetaData(decoderIndex);
|
2016-07-17 17:33:50 -04:00
|
|
|
|
|
|
|
if (!(*metaData == m_currentMeta))
|
|
|
|
{
|
|
|
|
int sampleRate = metaData->m_sampleRate;
|
|
|
|
|
|
|
|
if (sampleRate > 0) {
|
2018-09-09 15:26:47 -04:00
|
|
|
m_bufferLenSec = (float) m_framesNbBytes / (float) (sampleRate * m_currentMeta.m_sampleBytes * 2);
|
2016-07-17 17:33:50 -04:00
|
|
|
m_balCorrLimit = sampleRate / 1000; // +/- 1 ms correction max per read
|
2018-09-09 15:26:47 -04:00
|
|
|
m_readNbBytes = (sampleRate * m_currentMeta.m_sampleBytes * 2) / 20;
|
2016-07-17 17:33:50 -04:00
|
|
|
}
|
|
|
|
|
2017-06-09 08:18:11 -04:00
|
|
|
printMeta("SDRdaemonSourceBuffer::writeData: new meta", metaData); // print for change other than timestamp
|
2016-07-17 17:33:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
m_currentMeta = *metaData; // renew current meta
|
|
|
|
} // check block 0
|
|
|
|
} // decode
|
2016-07-06 20:36:44 -04:00
|
|
|
}
|
|
|
|
|
2017-06-09 08:14:32 -04:00
|
|
|
void SDRdaemonSourceBuffer::writeData0(char *array __attribute__((unused)), uint32_t length __attribute__((unused)))
|
2016-07-06 20:36:44 -04:00
|
|
|
{
|
2016-07-26 17:36:59 -04:00
|
|
|
// Kept as comments for the out of sync blocks algorithms
|
2016-07-06 21:49:47 -04:00
|
|
|
// assert(length == m_udpPayloadSize);
|
|
|
|
//
|
|
|
|
// bool dataAvailable = false;
|
|
|
|
// SuperBlock *superBlock = (SuperBlock *) array;
|
|
|
|
// int frameIndex = superBlock->header.frameIndex;
|
|
|
|
// int decoderIndex = frameIndex % nbDecoderSlots;
|
|
|
|
// int blockIndex = superBlock->header.blockIndex;
|
|
|
|
//
|
2017-06-09 08:18:11 -04:00
|
|
|
//// qDebug() << "SDRdaemonSourceBuffer::writeData:"
|
2016-07-06 21:49:47 -04:00
|
|
|
//// << " frameIndex: " << frameIndex
|
|
|
|
//// << " decoderIndex: " << decoderIndex
|
|
|
|
//// << " blockIndex: " << blockIndex;
|
|
|
|
//
|
|
|
|
// 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
|
|
|
|
// {
|
|
|
|
// int frameDelta = m_frameHead - frameIndex;
|
|
|
|
//
|
|
|
|
// if (frameDelta < 0)
|
|
|
|
// {
|
|
|
|
// if (-frameDelta < nbDecoderSlots) // new frame head not too new
|
|
|
|
// {
|
2017-06-09 08:18:11 -04:00
|
|
|
// //qDebug() << "SDRdaemonSourceBuffer::writeData: new frame head (1): " << frameIndex << ":" << frameDelta << ":" << decoderIndex;
|
2016-07-06 21:49:47 -04:00
|
|
|
// m_decoderIndexHead = decoderIndex; // new decoder slot head
|
|
|
|
// m_frameHead = frameIndex;
|
|
|
|
// checkSlotData(decoderIndex);
|
|
|
|
// dataAvailable = true;
|
|
|
|
// initDecodeSlot(decoderIndex); // collect stats and re-initialize current slot
|
|
|
|
// }
|
|
|
|
// else if (-frameDelta <= 65536 - nbDecoderSlots) // loss of sync start over
|
|
|
|
// {
|
2017-06-09 08:18:11 -04:00
|
|
|
// //qDebug() << "SDRdaemonSourceBuffer::writeData: loss of sync start over (1)" << frameIndex << ":" << frameDelta << ":" << decoderIndex;
|
2016-07-06 21:49:47 -04:00
|
|
|
// m_decoderIndexHead = decoderIndex; // new decoder slot head
|
|
|
|
// m_frameHead = frameIndex;
|
|
|
|
// initReadIndex(); // reset read index
|
|
|
|
// initDecodeAllSlots(); // re-initialize all slots
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// else
|
2016-07-06 20:54:23 -04:00
|
|
|
// {
|
2016-07-06 21:49:47 -04:00
|
|
|
// if (frameDelta > 65536 - nbDecoderSlots) // new frame head not too new
|
2016-07-06 20:54:23 -04:00
|
|
|
// {
|
2017-06-09 08:18:11 -04:00
|
|
|
// //qDebug() << "SDRdaemonSourceBuffer::writeData: new frame head (2): " << frameIndex << ":" << frameDelta << ":" << decoderIndex;
|
2016-07-06 21:49:47 -04:00
|
|
|
// m_decoderIndexHead = decoderIndex; // new decoder slot head
|
|
|
|
// m_frameHead = frameIndex;
|
|
|
|
// checkSlotData(decoderIndex);
|
|
|
|
// dataAvailable = true;
|
|
|
|
// initDecodeSlot(decoderIndex); // collect stats and re-initialize current slot
|
|
|
|
// }
|
|
|
|
// else if (frameDelta >= nbDecoderSlots) // loss of sync start over
|
|
|
|
// {
|
2017-06-09 08:18:11 -04:00
|
|
|
// //qDebug() << "SDRdaemonSourceBuffer::writeData: loss of sync start over (2)" << frameIndex << ":" << frameDelta << ":" << decoderIndex;
|
2016-07-06 21:49:47 -04:00
|
|
|
// m_decoderIndexHead = decoderIndex; // new decoder slot head
|
|
|
|
// m_frameHead = frameIndex;
|
|
|
|
// initReadIndex(); // reset read index
|
|
|
|
// initDecodeAllSlots(); // re-initialize all slots
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
2016-07-06 20:54:23 -04:00
|
|
|
//
|
2016-07-06 21:49:47 -04:00
|
|
|
// // decoderIndex should now be correctly set
|
|
|
|
//
|
2016-06-19 03:56:49 -04:00
|
|
|
}
|
|
|
|
|
2017-06-09 08:14:32 -04:00
|
|
|
uint8_t *SDRdaemonSourceBuffer::readData(int32_t length)
|
2016-06-19 03:56:49 -04:00
|
|
|
{
|
2016-06-19 18:45:24 -04:00
|
|
|
uint8_t *buffer = (uint8_t *) m_frames;
|
|
|
|
uint32_t readIndex = m_readIndex;
|
2016-06-19 03:56:49 -04:00
|
|
|
|
2016-07-12 21:31:19 -04:00
|
|
|
m_nbReads++;
|
|
|
|
|
2016-12-11 08:32:10 -05:00
|
|
|
// SEGFAULT FIX: arbitratily truncate so that it does not exceed buffer length
|
|
|
|
if (length > framesSize) {
|
|
|
|
length = framesSize;
|
|
|
|
}
|
|
|
|
|
2016-06-19 18:45:24 -04:00
|
|
|
if (m_readIndex + length < m_framesNbBytes) // ends before buffer bound
|
2016-06-19 03:56:49 -04:00
|
|
|
{
|
2016-06-19 18:45:24 -04:00
|
|
|
m_readIndex += length;
|
|
|
|
return &buffer[readIndex];
|
2016-06-19 03:56:49 -04:00
|
|
|
}
|
2016-06-19 18:45:24 -04:00
|
|
|
else if (m_readIndex + length == m_framesNbBytes) // ends at buffer bound
|
2016-06-19 03:56:49 -04:00
|
|
|
{
|
2016-06-19 18:45:24 -04:00
|
|
|
m_readIndex = 0;
|
|
|
|
return &buffer[readIndex];
|
2016-06-19 03:56:49 -04:00
|
|
|
}
|
2016-06-19 18:45:24 -04:00
|
|
|
else // ends after buffer bound
|
|
|
|
{
|
|
|
|
if (length > m_readSize) // reallocate composition buffer if necessary
|
|
|
|
{
|
|
|
|
if (m_readBuffer) {
|
|
|
|
delete[] m_readBuffer;
|
|
|
|
}
|
2016-06-19 03:56:49 -04:00
|
|
|
|
2016-06-19 18:45:24 -04:00
|
|
|
m_readBuffer = new uint8_t[length];
|
|
|
|
m_readSize = length;
|
|
|
|
}
|
2016-06-19 03:56:49 -04:00
|
|
|
|
2016-06-19 18:45:24 -04:00
|
|
|
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;
|
|
|
|
}
|
2016-06-19 03:56:49 -04:00
|
|
|
}
|
|
|
|
|
2017-06-09 08:14:32 -04:00
|
|
|
void SDRdaemonSourceBuffer::printMeta(const QString& header, MetaDataFEC *metaData)
|
2016-06-19 03:56:49 -04:00
|
|
|
{
|
|
|
|
qDebug() << header << ": "
|
2016-06-19 18:45:24 -04:00
|
|
|
<< "|" << 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
|
|
|
|
<< "|";
|
2016-06-19 03:56:49 -04:00
|
|
|
}
|