260 lines
7.8 KiB
C
260 lines
7.8 KiB
C
/* syncbuffs.c
|
|
|
|
This file is part of a program that implements a Software-Defined Radio.
|
|
|
|
Copyright (C) 2018 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@pratt.one
|
|
|
|
*/
|
|
|
|
#include "comm.h"
|
|
|
|
void start_syncbthread (SYNCB a)
|
|
{
|
|
HANDLE handle = (HANDLE) _beginthread(syncb_main, 0, (void *)a);
|
|
SetThreadPriority (handle, THREAD_PRIORITY_HIGHEST);
|
|
}
|
|
|
|
SYNCB create_syncbuffs (int accept, int nstreams, int max_insize, int max_outsize, int outsize, double** out, void (*exf)(void))
|
|
{
|
|
SYNCB a = (SYNCB) malloc0 (sizeof(syncb));
|
|
int i;
|
|
a->accept = accept;
|
|
a->nstreams = nstreams;
|
|
a->run = 1;
|
|
a->max_in_size = max_insize;
|
|
a->max_outsize = max_outsize;
|
|
a->r1_outsize = outsize;
|
|
a->out = out;
|
|
a->exf = exf;
|
|
if (a->max_outsize > a->max_in_size)
|
|
a->r1_size = a->max_outsize;
|
|
else
|
|
a->r1_size = a->max_in_size;
|
|
a->r1_active_buffsize = SYNCB_MULT * a->r1_size;
|
|
a->r1_baseptr = (double **) malloc0 (a->nstreams * sizeof (double *));
|
|
for (i = 0; i < a->nstreams; i++)
|
|
a->r1_baseptr[i] = (double *) malloc0 (a->r1_active_buffsize * sizeof (complex));
|
|
a->r1_inidx = 0;
|
|
a->r1_outidx = 0;
|
|
a->r1_unqueuedsamps = 0;
|
|
a->Sem_BuffReady = CreateSemaphore(0, 0, 1000, 0);
|
|
InitializeCriticalSectionAndSpinCount ( &a->csIN, 2500 );
|
|
InitializeCriticalSectionAndSpinCount ( &a->csOUT, 2500 );
|
|
start_syncbthread (a);
|
|
return a;
|
|
}
|
|
|
|
void destroy_syncbuffs (SYNCB a)
|
|
{
|
|
int i;
|
|
InterlockedBitTestAndReset(&a->accept, 0); // shut the Syncbound() gate to prevent new infusions
|
|
EnterCriticalSection (&a->csIN); // wait until the current Inbound() infusion is finished
|
|
EnterCriticalSection (&a->csOUT); // block the syncb thread before syncbdata()
|
|
Sleep (25); // wait for the thread to arrive at the top of the syncb_main() loop
|
|
InterlockedBitTestAndReset(&a->run, 0); // set a trap for the syncb thread
|
|
ReleaseSemaphore(a->Sem_BuffReady, 1, 0); // be sure the syncb thread can pass WaitForSingleObject in syncb_main() //
|
|
LeaveCriticalSection (&a->csOUT); // let the thread pass to the trap in syncbdata()
|
|
LeaveCriticalSection (&a->csIN);
|
|
Sleep (2); // wait for the syncb thread to die
|
|
DeleteCriticalSection (&a->csOUT);
|
|
DeleteCriticalSection (&a->csIN);
|
|
CloseHandle (a->Sem_BuffReady);
|
|
for (i = 0; i < a->nstreams; i++)
|
|
_aligned_free (a->r1_baseptr[i]);
|
|
_aligned_free (a->r1_baseptr);
|
|
_aligned_free (a);
|
|
}
|
|
|
|
void flush_syncbuffs (SYNCB a)
|
|
{
|
|
int i;
|
|
for (i = 0; i < a->nstreams; i++)
|
|
memset (a->r1_baseptr[i], 0, a->r1_active_buffsize * sizeof (complex));
|
|
a->r1_inidx = 0;
|
|
a->r1_outidx = 0;
|
|
a->r1_unqueuedsamps = 0;
|
|
while (!WaitForSingleObject (a->Sem_BuffReady, 1)) ;
|
|
}
|
|
|
|
void Syncbound (SYNCB a, int nsamples, double** in)
|
|
{
|
|
int i, n;
|
|
int first, second;
|
|
|
|
if (_InterlockedAnd (&a->accept, 1))
|
|
{
|
|
EnterCriticalSection (&a->csIN);
|
|
if (nsamples > (a->r1_active_buffsize - a->r1_inidx))
|
|
{
|
|
first = a->r1_active_buffsize - a->r1_inidx;
|
|
second = nsamples - first;
|
|
}
|
|
else
|
|
{
|
|
first = nsamples;
|
|
second = 0;
|
|
}
|
|
for (i = 0; i < a->nstreams; i++)
|
|
{
|
|
memcpy (a->r1_baseptr[i] + 2 * a->r1_inidx, in[i], first * sizeof (complex));
|
|
memcpy (a->r1_baseptr[i], in[i] + 2 * first, second * sizeof (complex));
|
|
}
|
|
if ((a->r1_unqueuedsamps += nsamples) >= 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 += nsamples) >= a->r1_active_buffsize)
|
|
a->r1_inidx -= a->r1_active_buffsize;
|
|
LeaveCriticalSection (&a->csIN);
|
|
}
|
|
}
|
|
|
|
void syncbdata (SYNCB a)
|
|
{
|
|
int i;
|
|
int first, second;
|
|
EnterCriticalSection (&a->csOUT);
|
|
if (!_InterlockedAnd (&a->run, 1))
|
|
{
|
|
LeaveCriticalSection (&a->csOUT);
|
|
_endthread();
|
|
}
|
|
if (a->r1_outsize > (a->r1_active_buffsize - a->r1_outidx))
|
|
{
|
|
first = a->r1_active_buffsize - a->r1_outidx;
|
|
second = a->r1_outsize - first;
|
|
}
|
|
else
|
|
{
|
|
first = a->r1_outsize;
|
|
second = 0;
|
|
}
|
|
for (i = 0; i < a->nstreams; i++)
|
|
{
|
|
memcpy (a->out[i], a->r1_baseptr[i] + 2 * a->r1_outidx, first * sizeof (complex));
|
|
memcpy (a->out[i] + 2 * first, a->r1_baseptr[i], second * sizeof (complex));
|
|
}
|
|
if ((a->r1_outidx += a->r1_outsize) >= a->r1_active_buffsize)
|
|
a->r1_outidx -= a->r1_active_buffsize;
|
|
LeaveCriticalSection (&a->csOUT);
|
|
}
|
|
|
|
void syncb_main (void *p)
|
|
{
|
|
SYNCB a = (SYNCB)p;
|
|
|
|
while (_InterlockedAnd (&a->run, 1))
|
|
{
|
|
WaitForSingleObject (a->Sem_BuffReady,INFINITE);
|
|
syncbdata (a);
|
|
a->exf();
|
|
}
|
|
_endthread();
|
|
}
|
|
|
|
void SetSYNCBRingOutsize (SYNCB a, int size)
|
|
{
|
|
InterlockedBitTestAndReset(&a->accept, 0); // shut the Syncbound() gate to prevent new infusions
|
|
EnterCriticalSection (&a->csIN); // wait until the current Syncbound() infusion is finished
|
|
EnterCriticalSection (&a->csOUT); // block the syncb thread before syncbdata()
|
|
Sleep (25); // wait for the thread to arrive at the top of the syncb_main() loop
|
|
InterlockedBitTestAndReset(&a->run, 0); // set a trap for the syncb thread
|
|
ReleaseSemaphore(a->Sem_BuffReady, 1, 0); // be sure the syncb thread can pass WaitForSingleObject in syncb_main() //
|
|
LeaveCriticalSection (&a->csOUT); // let the thread pass to the trap in syncbdata()
|
|
Sleep (2); // wait for the syncb thread to die
|
|
flush_syncbuffs(a); // restore ring to pristine condition
|
|
a->r1_outsize = size; // set its new outsize
|
|
InterlockedBitTestAndSet(&a->run,0); // remove the syncb thread trap
|
|
start_syncbthread(a); // start the syncb thread
|
|
LeaveCriticalSection (&a->csIN); // enable Syncbound() processing
|
|
InterlockedBitTestAndSet(&a->accept, 0); // open the Syncbound() gate
|
|
}
|
|
|
|
/********************************************************************************************************
|
|
* *
|
|
* Dummy Filter *
|
|
* *
|
|
********************************************************************************************************/
|
|
|
|
DUMFILT create_dumfilt (int run, int delay, int opsize, double* in, double* out)
|
|
{
|
|
DUMFILT a = (DUMFILT) malloc0 (sizeof (dumfilt));
|
|
a->run = run;
|
|
a->delay = delay;
|
|
a->opsize = opsize;
|
|
a->rsize = a->opsize + a->delay;
|
|
a->in = in;
|
|
a->out = out;
|
|
a->ring = (double *) malloc0 (a->rsize * sizeof (complex));
|
|
a->outidx = 0;
|
|
a->inidx = a->delay;
|
|
return a;
|
|
}
|
|
|
|
void destroy_dumfilt (DUMFILT a)
|
|
{
|
|
_aligned_free (a->ring);
|
|
_aligned_free (a);
|
|
}
|
|
|
|
void flush_dumfilt (DUMFILT a)
|
|
{
|
|
memset (a->ring, 0, a->rsize * sizeof (complex));
|
|
a->outidx = 0;
|
|
a->inidx = a->delay;
|
|
}
|
|
|
|
void xdumfilt (DUMFILT a)
|
|
{
|
|
int first, second;
|
|
if (a->run)
|
|
{
|
|
if (a->opsize > (a->rsize - a->inidx))
|
|
{
|
|
first = a->rsize - a->inidx;
|
|
second = a->opsize - first;
|
|
}
|
|
else
|
|
{
|
|
first = a->opsize;
|
|
second = 0;
|
|
}
|
|
memcpy (a->ring + 2 * a->inidx, a->in, first * sizeof (complex));
|
|
memcpy (a->ring, a->in + 2 * first, second * sizeof (complex));
|
|
if ((a->inidx += a->opsize) > a->rsize) a->inidx -= a->rsize;
|
|
if (a->opsize > a->rsize - a->outidx)
|
|
{
|
|
first = a->rsize - a->outidx;
|
|
second = a->opsize - first;
|
|
}
|
|
else
|
|
{
|
|
first = a->opsize;
|
|
second = 0;
|
|
}
|
|
memcpy (a->out, a->ring + 2 * a->outidx, first * sizeof (complex));
|
|
memcpy (a->out + 2 * first, a->ring, second * sizeof (complex));
|
|
if ((a->outidx += a->opsize) > a->rsize) a->outidx -= a->rsize;
|
|
}
|
|
}
|