wdsp/syncbuffs.c
Uladzimir Karpenka 89c8a0e2b5 first commit
2026-06-01 15:58:45 +03:00

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;
}
}