Imported Upstream version 3.2.2
[debian/gnuradio] / gr-gcell / src / gcell_fft_vcc.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2004,2007,2008 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <gcell_fft_vcc.h>
28 #include <gr_io_signature.h>
29 #include <gcell/gc_job_manager.h>
30 #include <gcell/gc_aligned_alloc.h>
31 #include <gcell/gcp_fft_1d_r2.h>
32 #include <math.h>
33 #include <assert.h>
34 #include <stdexcept>
35 #include <string.h>
36
37
38 #define MIN_FFT_SIZE      32
39 #define MAX_FFT_SIZE    4096
40
41 inline static bool
42 is_power_of_2(int x)
43 {
44   return x != 0 && (x & (x-1)) == 0;
45 }
46
47 static int 
48 int_log2(int x) // x is an exact power of 2
49 {
50   for (int i = 0; i < 32; i++)
51     if (x == (1 << i))
52       return i;
53
54   assert(0);
55 }
56
57 #if 0
58 gr_fft_vcc_sptr
59 gcell_make_fft_vcc(int fft_size, bool forward, const std::vector<float> &window, bool shift)
60 {
61   // If it doesn't meet our constraints, use standard implemenation
62   if (fft_size < MIN_FFT_SIZE || fft_size > MAX_FFT_SIZE
63       || !is_power_of_2(fft_size)
64       || (window.size() != 0 && fft_size > MAX_FFT_SIZE/2))
65     return gr_make_fft_vcc(fft_size, forward, window, shift);
66   else
67     return gr_fft_vcc_sptr (new gcell_fft_vcc(fft_size, forward, window, shift));
68 }
69 #else
70
71 gcell_fft_vcc_sptr
72 gcell_make_fft_vcc(int fft_size, bool forward, const std::vector<float> &window, bool shift)
73 {
74   return gcell_fft_vcc_sptr (new gcell_fft_vcc(fft_size, forward, window, shift));
75 }
76
77 #endif
78
79 gcell_fft_vcc::gcell_fft_vcc (int fft_size, bool forward,
80                               const std::vector<float> &window, bool shift)
81   : gr_fft_vcc("gcell_fft_vcc", fft_size, forward, window, shift)
82 {
83   if (fft_size < MIN_FFT_SIZE || fft_size > MAX_FFT_SIZE || !is_power_of_2(fft_size)){
84     throw std::invalid_argument("fft_size");
85   }
86
87   if (window.size() != 0 && fft_size > MAX_FFT_SIZE/2){
88     throw std::invalid_argument("fft_size too big to use window");
89   }
90
91   d_log2_fft_size = int_log2(fft_size);
92   d_mgr = gc_job_manager::singleton();          // grab the singleton job manager
93   d_twiddle_boost = gc_aligned_alloc_sptr(sizeof(std::complex<float>) * fft_size/4, 128);
94   d_twiddle = (std::complex<float>*) d_twiddle_boost.get();
95   gcp_fft_1d_r2_twiddle(d_log2_fft_size, d_twiddle);
96 }
97
98 gcell_fft_vcc::~gcell_fft_vcc ()
99 {
100 }
101
102 int
103 gcell_fft_vcc::work(int noutput_items,
104                     gr_vector_const_void_star &input_items,
105                     gr_vector_void_star &output_items)
106 {
107   const gr_complex *in = (const gr_complex *) input_items[0];
108   gr_complex *out = (gr_complex *) output_items[0];
109
110   // unsigned int input_data_size = input_signature()->sizeof_stream_item(0);
111   // unsigned int output_data_size = output_signature()->sizeof_stream_item(0);
112
113   float window_buf[MAX_FFT_SIZE/2] __attribute__((aligned (16)));
114   float *window = 0;
115   
116   // If we've got a window, ensure it's 16-byte aligned
117   // FIXME move this to set_window
118   if (d_window.size()){
119     if ((((intptr_t)&d_window[0]) & 0xf) == 0)
120       window = &d_window[0];            // OK as is
121     else {
122       window = window_buf;              // copy to aligned buffer
123       memcpy(window, &d_window[0], sizeof(float) * d_window.size());
124     }
125   }
126
127   std::vector<gc_job_desc_sptr> jd_sptr(noutput_items);
128   gc_job_desc *jd[noutput_items];
129   bool done[noutput_items];
130   
131   // submit noutput_items jobs in parallel
132
133   for (int i = 0; i < noutput_items; i++){
134     jd_sptr[i] = gcp_fft_1d_r2_submit(d_mgr, d_log2_fft_size,
135                                       d_forward, d_shift,
136                                       &out[i * d_fft_size],
137                                       &in[i * d_fft_size],
138                                       d_twiddle,
139                                       window);
140     jd[i] = jd_sptr[i].get();
141   }
142
143   int n = d_mgr->wait_jobs(noutput_items, jd, done, GC_WAIT_ALL);
144   if (n != noutput_items){
145     fprintf(stderr, "gcell_fft_vcc: wait_jobs returned %d, expected %d\n",
146             n, noutput_items);
147     return -1;
148   }
149
150   for (int i = 0; i < noutput_items; i++){
151     if (jd[i]->status != JS_OK){
152       fprintf(stderr, "gcell_fft_vcc jd[%d]->status = %s\n",
153               i, gc_job_status_string(jd[i]->status).c_str());
154       return -1;
155     }
156   }
157
158   return noutput_items;
159 }
160