/* 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]; } } }