220 lines
5.7 KiB
C
220 lines
5.7 KiB
C
/* div.c
|
|
|
|
This file is part of a program that implements a Software-Defined Radio.
|
|
|
|
Copyright (C) 2014 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"
|
|
|
|
#define MAX_NR (8) // maximum number of receivers to mix
|
|
|
|
MDIV create_div (int run, int nr, int size, double **in, double *out)
|
|
{
|
|
int i;
|
|
MDIV a = (MDIV) malloc0 (sizeof (mdiv));
|
|
a->run = run;
|
|
a->nr = nr;
|
|
a->size = size;
|
|
a->out = out;
|
|
a->in = (double **) malloc0 ( MAX_NR * sizeof (double *));
|
|
if (in != 0)
|
|
for (i = 0; i < nr; i++) a->in[i] = in[i];
|
|
a->Irotate = (double *) malloc0 (MAX_NR * sizeof (double));
|
|
a->Qrotate = (double *) malloc0 (MAX_NR * sizeof (double));
|
|
InitializeCriticalSectionAndSpinCount (&a->cs_update, 2500);
|
|
for (i = 0; i < 4; i++) ///////////// legacy interface - remove
|
|
a->legacy[i] = (double *) malloc0 (2048 * sizeof (complex)); ///////////// legacy interface - remove
|
|
return a;
|
|
}
|
|
|
|
void destroy_div (MDIV a)
|
|
{
|
|
int i; ///////////// legacy interface - remove
|
|
DeleteCriticalSection (&a->cs_update);
|
|
for (i = 0; i < 4; i++) ///////////// legacy interface - remove
|
|
_aligned_free (a->legacy[i]); ///////////// legacy interface - remove
|
|
_aligned_free (a->Qrotate);
|
|
_aligned_free (a->Irotate);
|
|
_aligned_free (a->in);
|
|
_aligned_free (a);
|
|
}
|
|
|
|
void flush_div (MDIV a)
|
|
{
|
|
|
|
}
|
|
|
|
void xdiv (MDIV a)
|
|
{
|
|
if (a->run)
|
|
{
|
|
EnterCriticalSection (&a->cs_update);
|
|
if (a->output != a->nr)
|
|
{
|
|
if (a->out != a->in[a->output])
|
|
memcpy (a->out, a->in[a->output], a->size * sizeof (complex));
|
|
}
|
|
else
|
|
{
|
|
int i, j;
|
|
double I, Q;
|
|
memset (a->out, 0, a->size * sizeof (complex));
|
|
for (i = 0; i < a->nr; i++)
|
|
for (j = 0; j < a->size; j++)
|
|
{
|
|
I = a->in[i][2 * j + 0];
|
|
Q = a->in[i][2 * j + 1];
|
|
a->out[2 * j + 0] += a->Irotate[i] * I - a->Qrotate[i] * Q;
|
|
a->out[2 * j + 1] += a->Irotate[i] * Q + a->Qrotate[i] * I;
|
|
}
|
|
}
|
|
LeaveCriticalSection (&a->cs_update);
|
|
}
|
|
else
|
|
memcpy (a->out, a->in[0], a->size * sizeof (complex));
|
|
}
|
|
|
|
|
|
/********************************************************************************************************
|
|
* *
|
|
* CALLS FOR EXTERNAL USE *
|
|
* *
|
|
********************************************************************************************************/
|
|
|
|
#define MAX_EXT_DIVS (2) // maximum number of DIVs called from outside wdsp
|
|
__declspec (align (16)) MDIV pdiv[MAX_EXT_DIVS]; // array of pointers for DIVs used EXTERNAL to wdsp
|
|
|
|
PORT
|
|
void create_divEXT (int id, int run, int nr, int size)
|
|
{
|
|
pdiv[id] = create_div (run, nr, size, 0, 0);
|
|
}
|
|
|
|
PORT
|
|
void destroy_divEXT (int id)
|
|
{
|
|
destroy_div (pdiv[id]);
|
|
}
|
|
|
|
PORT
|
|
void flush_divEXT (int id)
|
|
{
|
|
flush_div (pdiv[id]);
|
|
}
|
|
|
|
PORT
|
|
void xdivEXT (int id, int nsamples, double **in, double *out)
|
|
{
|
|
int i;
|
|
MDIV a = pdiv[id];
|
|
a->size = nsamples;
|
|
a->out = out;
|
|
for (i = 0; i < a->nr; i++) a->in[i] = in[i];
|
|
xdiv (a);
|
|
}
|
|
|
|
// 0 - does nothing; 1 - operates
|
|
PORT
|
|
void SetEXTDIVRun (int id, int run)
|
|
{
|
|
MDIV a = pdiv[id];
|
|
EnterCriticalSection (&a->cs_update);
|
|
a->run = run;
|
|
LeaveCriticalSection (&a->cs_update);
|
|
}
|
|
|
|
// size of data buffer in complex samples
|
|
PORT
|
|
void SetEXTDIVBuffsize (int id, int size)
|
|
{
|
|
MDIV a = pdiv[id];
|
|
EnterCriticalSection (&a->cs_update);
|
|
a->size = size;
|
|
LeaveCriticalSection (&a->cs_update);
|
|
}
|
|
|
|
// number of receivers being used for diversity
|
|
PORT
|
|
void SetEXTDIVNr (int id, int nr)
|
|
{
|
|
MDIV a = pdiv[id];
|
|
EnterCriticalSection (&a->cs_update);
|
|
a->nr = nr;
|
|
LeaveCriticalSection (&a->cs_update);
|
|
}
|
|
|
|
// number of which receiver to output
|
|
// if output==nr, mixing occurs
|
|
PORT
|
|
void SetEXTDIVOutput (int id, int output)
|
|
{
|
|
MDIV a = pdiv[id];
|
|
EnterCriticalSection (&a->cs_update);
|
|
a->output = output;
|
|
LeaveCriticalSection (&a->cs_update);
|
|
}
|
|
|
|
// I and Q "rotate" multipliers for each receiver
|
|
// can be set to 1.0 and 0.0 for "reference receiver"
|
|
PORT
|
|
void SetEXTDIVRotate (int id, int nr, double *Irotate, double *Qrotate)
|
|
{
|
|
MDIV a = pdiv[id];
|
|
EnterCriticalSection (&a->cs_update);
|
|
memcpy (a->Irotate, Irotate, nr * sizeof (double));
|
|
memcpy (a->Qrotate, Qrotate, nr * sizeof (double));
|
|
LeaveCriticalSection (&a->cs_update);
|
|
}
|
|
|
|
/********************************************************************************************************
|
|
* *
|
|
* LEGACY INTERFACE - REMOVE *
|
|
* *
|
|
********************************************************************************************************/
|
|
PORT
|
|
void xdivEXTF (int id, int size, float **input, float *Iout, float *Qout)
|
|
{
|
|
int i, j;
|
|
MDIV a = pdiv[id];
|
|
if (a->run)
|
|
{
|
|
a->size = size;
|
|
for (i = 0; i < a->nr; i++)
|
|
{
|
|
for (j = 0; j < a->size; j++)
|
|
{
|
|
a->legacy[i][2 * j + 0] = (double)input[2 * i + 0][j];
|
|
a->legacy[i][2 * j + 1] = (double)input[2 * i + 1][j];
|
|
}
|
|
a->in[i] = a->legacy[i];
|
|
}
|
|
a->out = a->legacy[3];
|
|
xdiv (a);
|
|
for (j = 0; j < a->size; j++)
|
|
{
|
|
Iout[j] = (float)a->legacy[3][2 * j + 0];
|
|
Qout[j] = (float)a->legacy[3][2 * j + 1];
|
|
}
|
|
}
|
|
}
|