605 lines
15 KiB
C
605 lines
15 KiB
C
/* iobuffs.c
|
|
|
|
This file is part of a program that implements a Software-Defined Radio.
|
|
|
|
Copyright (C) 2013 Warren Pratt, NR0V
|
|
|
|
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; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
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 for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
The author can be reached by email at
|
|
|
|
warren@wpratt.com
|
|
|
|
*/
|
|
|
|
#include "comm.h"
|
|
|
|
/********************************************************************************************************
|
|
* *
|
|
* Begin Slew Code *
|
|
* *
|
|
********************************************************************************************************/
|
|
|
|
enum _slew
|
|
{
|
|
BEGIN = 0,
|
|
DELAYUP,
|
|
UPSLEW,
|
|
ON,
|
|
DELAYDOWN,
|
|
DOWNSLEW,
|
|
ZERO,
|
|
OFF
|
|
};
|
|
|
|
void create_slews (IOB a)
|
|
{
|
|
int i;
|
|
double delta, theta;
|
|
a->slew.ustate = BEGIN;
|
|
a->slew.dstate = BEGIN;
|
|
a->slew.ucount = 0;
|
|
a->slew.dcount = 0;
|
|
a->slew.ndelup = (int)(ch[a->channel].tdelayup * ch[a->channel].in_rate);
|
|
a->slew.ndeldown = (int)(ch[a->channel].tdelaydown * ch[a->channel].out_rate);
|
|
a->slew.ntup = (int)(ch[a->channel].tslewup * ch[a->channel].in_rate);
|
|
a->slew.ntdown = (int)(ch[a->channel].tslewdown * ch[a->channel].out_rate);
|
|
a->slew.cup = (double *) malloc0 ((a->slew.ntup + 1) * sizeof (double));
|
|
a->slew.cdown = (double *) malloc0 ((a->slew.ntdown + 1) * sizeof (double));
|
|
|
|
delta = PI / (double)a->slew.ntup;
|
|
theta = 0.0;
|
|
for (i = 0; i <= a->slew.ntup; i++)
|
|
{
|
|
a->slew.cup[i] = 0.5 * (1.0 - cos (theta));
|
|
theta += delta;
|
|
}
|
|
|
|
delta = PI / (double)a->slew.ntdown;
|
|
theta = 0.0;
|
|
for (i = 0; i <= a->slew.ntdown; i++)
|
|
{
|
|
a->slew.cdown[i] = 0.5 * (1 + cos (theta));
|
|
theta += delta;
|
|
}
|
|
|
|
InterlockedBitTestAndReset (&a->slew.upflag, 0);
|
|
InterlockedBitTestAndReset (&a->slew.downflag, 0);
|
|
}
|
|
|
|
void destroy_slews(IOB a)
|
|
{
|
|
_aligned_free (a->slew.cdown);
|
|
_aligned_free (a->slew.cup);
|
|
}
|
|
|
|
void flush_slews (IOB a)
|
|
{
|
|
a->slew.ustate = BEGIN;
|
|
a->slew.dstate = BEGIN;
|
|
a->slew.ucount = 0;
|
|
a->slew.dcount = 0;
|
|
InterlockedBitTestAndReset (&a->slew.upflag, 0);
|
|
InterlockedBitTestAndReset (&a->slew.downflag, 0);
|
|
}
|
|
|
|
void upslew0 (IOB a, double* pin)
|
|
{
|
|
int i;
|
|
double *pout;
|
|
double I, Q;
|
|
pout = a->r1_baseptr + 2 * a->r1_inidx;
|
|
for (i = 0; i < a->in_size; i++)
|
|
{
|
|
I = pin[2 * i + 0];
|
|
Q = pin[2 * i + 1];
|
|
switch (a->slew.ustate)
|
|
{
|
|
case BEGIN:
|
|
pout[2 * i + 0] = 0.0;
|
|
pout[2 * i + 1] = 0.0;
|
|
if ((I != 0.0) || (Q != 0.0))
|
|
{
|
|
if (a->slew.ndelup > 0)
|
|
{
|
|
a->slew.ustate = DELAYUP;
|
|
a->slew.ucount = a->slew.ndelup;
|
|
}
|
|
else if (a->slew.ntup > 0)
|
|
{
|
|
a->slew.ustate = UPSLEW;
|
|
a->slew.ucount = a->slew.ntup;
|
|
}
|
|
else
|
|
a->slew.ustate = ON;
|
|
}
|
|
break;
|
|
case DELAYUP:
|
|
pout[2 * i + 0] = 0.0;
|
|
pout[2 * i + 1] = 0.0;
|
|
if (a->slew.ucount-- == 0)
|
|
{
|
|
if (a->slew.ntup > 0)
|
|
{
|
|
a->slew.ustate = UPSLEW;
|
|
a->slew.ucount = a->slew.ntup;
|
|
}
|
|
else
|
|
a->slew.ustate = ON;
|
|
}
|
|
break;
|
|
case UPSLEW:
|
|
pout[2 * i + 0] = I * a->slew.cup[a->slew.ntup - a->slew.ucount];
|
|
pout[2 * i + 1] = Q * a->slew.cup[a->slew.ntup - a->slew.ucount];
|
|
if (a->slew.ucount-- == 0)
|
|
a->slew.ustate = ON;
|
|
break;
|
|
case ON:
|
|
pout[2 * i + 0] = I;
|
|
pout[2 * i + 1] = Q;
|
|
if (i == a->in_size - 1)
|
|
{
|
|
a->slew.ustate = BEGIN;
|
|
InterlockedBitTestAndReset (&a->slew.upflag, 0);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void upslew2 (IOB a, INREAL* pIin, INREAL* pQin)
|
|
{
|
|
int i;
|
|
double *pout;
|
|
double I, Q;
|
|
pout = a->r1_baseptr + 2 * a->r1_inidx;
|
|
for (i = 0; i < a->in_size; i++)
|
|
{
|
|
I = (double)pIin[i];
|
|
Q = (double)pQin[i];
|
|
switch (a->slew.ustate)
|
|
{
|
|
case BEGIN:
|
|
pout[2 * i + 0] = 0.0;
|
|
pout[2 * i + 1] = 0.0;
|
|
if ((I != 0.0) || (Q != 0.0))
|
|
{
|
|
if (a->slew.ndelup > 0)
|
|
{
|
|
a->slew.ustate = DELAYUP;
|
|
a->slew.ucount = a->slew.ndelup;
|
|
}
|
|
else if (a->slew.ntup > 0)
|
|
{
|
|
a->slew.ustate = UPSLEW;
|
|
a->slew.ucount = a->slew.ntup;
|
|
}
|
|
else
|
|
a->slew.ustate = ON;
|
|
}
|
|
break;
|
|
case DELAYUP:
|
|
pout[2 * i + 0] = 0.0;
|
|
pout[2 * i + 1] = 0.0;
|
|
if (a->slew.ucount-- == 0)
|
|
{
|
|
if (a->slew.ntup > 0)
|
|
{
|
|
a->slew.ustate = UPSLEW;
|
|
a->slew.ucount = a->slew.ntup;
|
|
}
|
|
else
|
|
a->slew.ustate = ON;
|
|
}
|
|
break;
|
|
case UPSLEW:
|
|
pout[2 * i + 0] = I * a->slew.cup[a->slew.ntup - a->slew.ucount];
|
|
pout[2 * i + 1] = Q * a->slew.cup[a->slew.ntup - a->slew.ucount];
|
|
if (a->slew.ucount-- == 0)
|
|
a->slew.ustate = ON;
|
|
break;
|
|
case ON:
|
|
pout[2 * i + 0] = I;
|
|
pout[2 * i + 1] = Q;
|
|
if (i == a->in_size - 1)
|
|
{
|
|
a->slew.ustate = BEGIN;
|
|
InterlockedBitTestAndReset (&a->slew.upflag, 0);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void downslew0 (IOB a, double* pout)
|
|
{
|
|
int i;
|
|
double *pin;
|
|
double I, Q;
|
|
pin = a->r2_baseptr + 2 * a->r2_outidx;
|
|
for (i = 0; i < a->out_size; i++)
|
|
{
|
|
I = pin[2 * i + 0];
|
|
Q = pin[2 * i + 1];
|
|
switch (a->slew.dstate)
|
|
{
|
|
case BEGIN:
|
|
pout[2 * i + 0] = I;
|
|
pout[2 * i + 1] = Q;
|
|
if (a->slew.ndeldown > 0)
|
|
{
|
|
a->slew.dstate = DELAYDOWN;
|
|
a->slew.dcount = a->slew.ndeldown;
|
|
}
|
|
else if (a->slew.ntdown > 0)
|
|
{
|
|
a->slew.dstate = DOWNSLEW;
|
|
a->slew.dcount = a->slew.ntdown;
|
|
}
|
|
else
|
|
{
|
|
a->slew.dstate = ZERO;
|
|
a->slew.dcount = a->out_size;
|
|
}
|
|
break;
|
|
case DELAYDOWN:
|
|
pout[2 * i + 0] = I;
|
|
pout[2 * i + 1] = Q;
|
|
if (a->slew.dcount-- == 0)
|
|
{
|
|
if (a->slew.ntdown > 0)
|
|
{
|
|
a->slew.dstate = DOWNSLEW;
|
|
a->slew.dcount = a->slew.ntdown;
|
|
}
|
|
else
|
|
{
|
|
a->slew.dstate = ZERO;
|
|
a->slew.dcount = a->out_size;
|
|
}
|
|
}
|
|
break;
|
|
case DOWNSLEW:
|
|
pout[2 * i + 0] = I * a->slew.cdown[a->slew.ntdown - a->slew.dcount];
|
|
pout[2 * i + 1] = Q * a->slew.cdown[a->slew.ntdown - a->slew.dcount];
|
|
if (a->slew.dcount-- == 0)
|
|
{
|
|
a->slew.dstate = ZERO;
|
|
a->slew.dcount = a->out_size;
|
|
}
|
|
break;
|
|
case ZERO:
|
|
pout[2 * i + 0] = 0.0;
|
|
pout[2 * i + 1] = 0.0;
|
|
if (a->slew.dcount-- == 0)
|
|
a->slew.dstate = OFF;
|
|
break;
|
|
case OFF:
|
|
pout[2 * i + 0] = 0.0;
|
|
pout[2 * i + 1] = 0.0;
|
|
if (i == a->out_size - 1)
|
|
{
|
|
a->slew.dstate = BEGIN;
|
|
InterlockedBitTestAndReset (&a->slew.downflag, 0);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void downslew2 (IOB a, OUTREAL* pIout, OUTREAL* pQout)
|
|
{
|
|
int i;
|
|
double *pin;
|
|
double I, Q;
|
|
pin = a->r2_baseptr + 2 * a->r2_outidx;
|
|
for (i = 0; i < a->out_size; i++)
|
|
{
|
|
I = pin[2 * i + 0];
|
|
Q = pin[2 * i + 1];
|
|
switch (a->slew.dstate)
|
|
{
|
|
case BEGIN:
|
|
pIout[i] = (OUTREAL)I;
|
|
pQout[i] = (OUTREAL)Q;
|
|
if (a->slew.ndeldown > 0)
|
|
{
|
|
a->slew.dstate = DELAYDOWN;
|
|
a->slew.dcount = a->slew.ndeldown;
|
|
}
|
|
else if (a->slew.ntdown > 0)
|
|
{
|
|
a->slew.dstate = DOWNSLEW;
|
|
a->slew.dcount = a->slew.ntdown;
|
|
}
|
|
else
|
|
{
|
|
a->slew.dstate = ZERO;
|
|
a->slew.dcount = a->out_size;
|
|
}
|
|
break;
|
|
case DELAYDOWN:
|
|
pIout[i] = (OUTREAL)I;
|
|
pQout[i] = (OUTREAL)Q;
|
|
if (a->slew.dcount-- == 0)
|
|
{
|
|
if (a->slew.ntdown > 0)
|
|
{
|
|
a->slew.dstate = DOWNSLEW;
|
|
a->slew.dcount = a->slew.ntdown;
|
|
}
|
|
else
|
|
{
|
|
a->slew.dstate = ZERO;
|
|
a->slew.dcount = a->out_size;
|
|
}
|
|
}
|
|
break;
|
|
case DOWNSLEW:
|
|
pIout[i] = (OUTREAL)(I * a->slew.cdown[a->slew.ntdown - a->slew.dcount]);
|
|
pQout[i] = (OUTREAL)(Q * a->slew.cdown[a->slew.ntdown - a->slew.dcount]);
|
|
if (a->slew.dcount-- == 0)
|
|
{
|
|
a->slew.dstate = ZERO;
|
|
a->slew.dcount = a->out_size;
|
|
}
|
|
break;
|
|
case ZERO:
|
|
pIout[i] = 0.0;
|
|
pQout[i] = 0.0;
|
|
if (a->slew.dcount-- == 0)
|
|
a->slew.dstate = OFF;
|
|
break;
|
|
case OFF:
|
|
pIout[i] = 0.0;
|
|
pQout[i] = 0.0;
|
|
if (i == a->out_size - 1)
|
|
{
|
|
a->slew.dstate = BEGIN;
|
|
InterlockedBitTestAndReset (&a->slew.downflag, 0);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/********************************************************************************************************
|
|
* *
|
|
* Begin Buffer Code *
|
|
* *
|
|
********************************************************************************************************/
|
|
|
|
void create_iobuffs (int channel)
|
|
{
|
|
int n;
|
|
IOB a = (IOB) malloc0 (sizeof(iob));
|
|
ch[channel].iob.pc = ch[channel].iob.pd = ch[channel].iob.pe = ch[channel].iob.pf = a;
|
|
a->channel = channel;
|
|
a->in_size = ch[channel].in_size;
|
|
a->r1_outsize = ch[channel].dsp_insize;
|
|
if (a->r1_outsize > a->in_size)
|
|
a->r1_size = a->r1_outsize;
|
|
else
|
|
a->r1_size = a->in_size;
|
|
a->out_size = ch[channel].out_size;
|
|
a->r2_insize = ch[channel].dsp_outsize;
|
|
if (a->out_size > a->r2_insize)
|
|
a->r2_size = a->out_size;
|
|
else
|
|
a->r2_size = a->r2_insize;
|
|
a->r1_active_buffsize = DSP_MULT * a->r1_size;
|
|
a->r2_active_buffsize = DSP_MULT * a->r2_size;
|
|
a->r1_baseptr = (double*) malloc0 (a->r1_active_buffsize * sizeof (complex));
|
|
a->r2_baseptr = (double*) malloc0 (a->r2_active_buffsize * sizeof (complex));
|
|
a->r1_inidx = 0;
|
|
a->r1_outidx = 0;
|
|
a->r1_unqueuedsamps = 0;
|
|
a->r2_inidx = (DSP_MULT - 1) * a->r2_size;
|
|
a->r2_outidx = 0;
|
|
a->r2_havesamps = (DSP_MULT - 1) * a->r2_size;
|
|
n = a->r2_havesamps / a->out_size;
|
|
a->r2_unqueuedsamps = a->r2_havesamps - n * a->out_size;
|
|
InitializeCriticalSectionAndSpinCount(&a->r2_ControlSection, 2500);
|
|
a->Sem_BuffReady = CreateSemaphore(0, 0, 1000, 0);
|
|
a->Sem_OutReady = CreateSemaphore(0, n, 1000, 0);
|
|
a->bfo = ch[channel].bfo;
|
|
create_slews (a);
|
|
|
|
InterlockedBitTestAndReset(&a->flush_bypass, 0);
|
|
a->Sem_Flush = CreateSemaphore(0, 0, 1, 0);
|
|
_beginthread(flushChannel, 0, (void*)(uintptr_t)a->channel);
|
|
}
|
|
|
|
void destroy_iobuffs (int channel)
|
|
{
|
|
IOB a = ch[channel].iob.pc;
|
|
|
|
InterlockedBitTestAndSet(&a->flush_bypass, 0);
|
|
ReleaseSemaphore(a->Sem_Flush, 1, 0);
|
|
while (InterlockedAnd(&a->flush_bypass, 0xffffffff)) Sleep(1);
|
|
CloseHandle(a->Sem_Flush);
|
|
|
|
destroy_slews (a);
|
|
CloseHandle (a->Sem_OutReady);
|
|
CloseHandle (a->Sem_BuffReady);
|
|
DeleteCriticalSection(&a->r2_ControlSection);
|
|
_aligned_free (a->r2_baseptr);
|
|
_aligned_free (a->r1_baseptr);
|
|
_aligned_free (a);
|
|
}
|
|
|
|
void flush_iobuffs (int channel)
|
|
{
|
|
int n;
|
|
IOB a = ch[channel].iob.pf;
|
|
memset (a->r1_baseptr, 0, a->r1_active_buffsize * sizeof (complex));
|
|
memset (a->r2_baseptr, 0, a->r2_active_buffsize * sizeof (complex));
|
|
a->r1_inidx = 0;
|
|
a->r1_outidx = 0;
|
|
a->r1_unqueuedsamps = 0;
|
|
a->r2_inidx = (DSP_MULT - 1) * a->r2_size;
|
|
a->r2_outidx = 0;
|
|
a->r2_havesamps = (DSP_MULT - 1) * a->r2_size;
|
|
while (!WaitForSingleObject (a->Sem_BuffReady, 1));
|
|
n = a->r2_havesamps / a->out_size;
|
|
a->r2_unqueuedsamps = a->r2_havesamps - n * a->out_size;
|
|
CloseHandle (a->Sem_OutReady);
|
|
a->Sem_OutReady = CreateSemaphore(0, n, 1000, 0);
|
|
flush_slews (a);
|
|
}
|
|
|
|
|
|
PORT //double, interleaved I/Q
|
|
void fexchange0 (int channel, double* in, double* out, int* error)
|
|
{
|
|
int n;
|
|
int doit = 0;
|
|
IOB a;
|
|
*error = 0;
|
|
if (_InterlockedAnd (&ch[channel].exchange, 1))
|
|
{
|
|
EnterCriticalSection (&ch[channel].csEXCH);
|
|
a = ch[channel].iob.pe;
|
|
if (_InterlockedAnd (&a->slew.upflag, 1))
|
|
upslew0 (a, in);
|
|
else
|
|
memcpy (a->r1_baseptr + 2 * a->r1_inidx, in, a->in_size * sizeof (complex));
|
|
// add check with *error += -1; for case when r1 is full and an overwrite occurs
|
|
if ((a->r1_unqueuedsamps += a->in_size) >= a->r1_outsize)
|
|
{
|
|
n = a->r1_unqueuedsamps / a->r1_outsize;
|
|
ReleaseSemaphore(a->Sem_BuffReady, n, 0);
|
|
a->r1_unqueuedsamps -= n * a->r1_outsize;
|
|
}
|
|
if ((a->r1_inidx += a->in_size) == a->r1_active_buffsize)
|
|
a->r1_inidx = 0;
|
|
|
|
EnterCriticalSection (&a->r2_ControlSection);
|
|
if (a->r2_havesamps >= a->out_size)
|
|
doit = 1;
|
|
if ((a->r2_havesamps -= a->out_size) < 0) a->r2_havesamps = 0;
|
|
LeaveCriticalSection (&a->r2_ControlSection);
|
|
if (a->bfo) WaitForSingleObject (a->Sem_OutReady, INFINITE);
|
|
if (a->bfo || doit)
|
|
if (_InterlockedAnd (&a->slew.downflag, 1))
|
|
{
|
|
downslew0 (a, out);
|
|
if (!_InterlockedAnd (&a->slew.downflag, 1))
|
|
{
|
|
InterlockedBitTestAndReset (&ch[channel].exchange, 0);
|
|
ReleaseSemaphore(a->Sem_Flush, 1, 0);
|
|
}
|
|
}
|
|
else
|
|
memcpy (out, a->r2_baseptr + 2 * a->r2_outidx, a->out_size * sizeof (complex));
|
|
else
|
|
{
|
|
memset (out, 0, a->out_size * sizeof (complex));
|
|
*error += -2;
|
|
}
|
|
if ((a->r2_outidx += a->out_size) == a->r2_active_buffsize)
|
|
a->r2_outidx = 0;
|
|
LeaveCriticalSection (&ch[channel].csEXCH);
|
|
}
|
|
}
|
|
|
|
PORT //separate I/Q buffers
|
|
void fexchange2 (int channel, INREAL *Iin, INREAL *Qin, OUTREAL *Iout, OUTREAL *Qout, int* error)
|
|
{
|
|
int i, n;
|
|
int doit = 0;
|
|
IOB a;
|
|
*error = 0;
|
|
if (_InterlockedAnd (&ch[channel].exchange, 1))
|
|
{
|
|
EnterCriticalSection (&ch[channel].csEXCH);
|
|
a = ch[channel].iob.pe;
|
|
if (_InterlockedAnd (&a->slew.upflag, 1))
|
|
upslew2 (a, Iin, Qin);
|
|
else
|
|
for (i = 0; i < a->in_size; i++)
|
|
{
|
|
(a->r1_baseptr + 2 * a->r1_inidx)[2 * i + 0] = (double)(Iin[i]);
|
|
(a->r1_baseptr + 2 * a->r1_inidx)[2 * i + 1] = (double)(Qin[i]);
|
|
}
|
|
// add check with *error += -1; for case when r1 is full and an overwrite occurs
|
|
if ((a->r1_unqueuedsamps += a->in_size) >= a->r1_outsize)
|
|
{
|
|
n = a->r1_unqueuedsamps / a->r1_outsize;
|
|
ReleaseSemaphore(a->Sem_BuffReady, n, 0);
|
|
a->r1_unqueuedsamps -= n * a->r1_outsize;
|
|
}
|
|
if ((a->r1_inidx += a->in_size) == a->r1_active_buffsize)
|
|
a->r1_inidx = 0;
|
|
|
|
EnterCriticalSection (&a->r2_ControlSection);
|
|
if (a->r2_havesamps >= a->out_size)
|
|
doit = 1;
|
|
if ((a->r2_havesamps -= a->out_size) < 0) a->r2_havesamps = 0;
|
|
LeaveCriticalSection (&a->r2_ControlSection);
|
|
if (a->bfo) WaitForSingleObject (a->Sem_OutReady, INFINITE);
|
|
if (a->bfo || doit)
|
|
{
|
|
if (_InterlockedAnd (&a->slew.downflag, 1))
|
|
{
|
|
downslew2 (a, Iout, Qout);
|
|
if (!_InterlockedAnd (&a->slew.downflag, 1))
|
|
{
|
|
InterlockedBitTestAndReset (&ch[channel].exchange, 0);
|
|
ReleaseSemaphore(a->Sem_Flush, 1, 0);
|
|
}
|
|
}
|
|
else
|
|
for (i = 0; i < a->out_size; i++)
|
|
{
|
|
Iout[i] = (OUTREAL)((a->r2_baseptr + 2 * a->r2_outidx)[2 * i + 0]);
|
|
Qout[i] = (OUTREAL)((a->r2_baseptr + 2 * a->r2_outidx)[2 * i + 1]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
memset (Iout, 0, a->out_size * sizeof (OUTREAL));
|
|
memset (Qout, 0, a->out_size * sizeof (OUTREAL));
|
|
*error += -2;
|
|
}
|
|
if ((a->r2_outidx += a->out_size) == a->r2_active_buffsize)
|
|
a->r2_outidx = 0;
|
|
LeaveCriticalSection (&ch[channel].csEXCH);
|
|
}
|
|
}
|
|
|
|
void dexchange (int channel, double* in, double* out)
|
|
{
|
|
int n;
|
|
IOB a = ch[channel].iob.pd;
|
|
if (!_InterlockedAnd (&ch[channel].run, 1)) _endthread();
|
|
|
|
EnterCriticalSection (&a->r2_ControlSection);
|
|
a->r2_havesamps += a->r2_insize;
|
|
LeaveCriticalSection (&a->r2_ControlSection);
|
|
memcpy (a->r2_baseptr + 2 * a->r2_inidx, in, a->r2_insize * sizeof (complex));
|
|
if ((a->r2_inidx += a->r2_insize) == a->r2_active_buffsize)
|
|
a->r2_inidx = 0;
|
|
if (a->bfo && (a->r2_unqueuedsamps += a->r2_insize) >= a->out_size)
|
|
{
|
|
n = a->r2_unqueuedsamps / a->out_size;
|
|
ReleaseSemaphore(a->Sem_OutReady, n, 0);
|
|
a->r2_unqueuedsamps -= n * a->out_size;
|
|
}
|
|
memcpy (out, a->r1_baseptr + 2 * a->r1_outidx, a->r1_outsize * sizeof (complex));
|
|
if ((a->r1_outidx += a->r1_outsize) == a->r1_active_buffsize)
|
|
a->r1_outidx = 0;
|
|
}
|