blob: 8e921b1583af039fc473a780d2b6721e763c6b72 [file] [log] [blame]
Thomas Tsoue90a42b2013-11-13 23:38:09 -05001/*
2 * SSE Convolution
3 * Copyright (C) 2013 Thomas Tsou <tom@tsou.cc>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <radioInterface.h>
21#include <Logger.h>
22
23#include "Resampler.h"
24
25extern "C" {
26#include "convert.h"
27}
28
29/* Resampling parameters for 64 MHz clocking */
30#define RESAMP_64M_INRATE 20
31#define RESAMP_64M_OUTRATE 80
32
33/* Downlink block size */
34#define CHUNK 625
35
36/* Universal resampling parameters */
37#define NUMCHUNKS 48
38
39/*
40 * Resampling filter bandwidth scaling factor
41 * This narrows the filter cutoff relative to the output bandwidth
42 * of the polyphase resampler. At 4 samples-per-symbol using the
43 * 2 pulse Laurent GMSK approximation gives us below 0.5 degrees
44 * RMS phase error at the resampler output.
45 */
46#define RESAMP_TX4_FILTER 0.45
47
48static size_t resamp_inrate = 0;
49static size_t resamp_inchunk = 0;
50static size_t resamp_outrate = 0;
51static size_t resamp_outchunk = 0;
52
53RadioInterfaceDiversity::RadioInterfaceDiversity(RadioDevice *wRadio,
54 size_t sps, size_t chans)
55 : RadioInterface(wRadio, sps, chans, 2), outerRecvBuffer(NULL),
56 mDiversity(false), mFreqSpacing(0.0)
57{
58}
59
60RadioInterfaceDiversity::~RadioInterfaceDiversity()
61{
62 close();
63}
64
65void RadioInterfaceDiversity::close()
66{
67 delete outerRecvBuffer;
68
69 outerRecvBuffer = NULL;
70
71 for (size_t i = 0; i < dnsamplers.size(); i++) {
72 delete dnsamplers[i];
73 dnsamplers[i] = NULL;
74 }
75
76 if (recvBuffer.size())
77 recvBuffer[0] = NULL;
78
79 RadioInterface::close();
80}
81
82bool RadioInterfaceDiversity::setupDiversityChannels()
83{
84 size_t inner_rx_len;
85
86 /* Inner and outer rates */
87 resamp_inrate = RESAMP_64M_INRATE;
88 resamp_outrate = RESAMP_64M_OUTRATE;
89 resamp_inchunk = resamp_inrate * 4;
90 resamp_outchunk = resamp_outrate * 4;
91
92 /* Buffer lengths */
93 inner_rx_len = NUMCHUNKS * resamp_inchunk;
94
95 /* Inside buffer must hold at least 2 bursts */
96 if (inner_rx_len < 157 * mSPSRx * 2) {
97 LOG(ALERT) << "Invalid inner buffer size " << inner_rx_len;
98 return false;
99 }
100
101 /* One Receive buffer and downsampler per diversity channel */
102 for (size_t i = 0; i < mMIMO * mChans; i++) {
103 dnsamplers[i] = new Resampler(resamp_inrate, resamp_outrate);
104 if (!dnsamplers[i]->init()) {
105 LOG(ALERT) << "Rx resampler failed to initialize";
106 return false;
107 }
108
109 recvBuffer[i] = new signalVector(inner_rx_len);
110 }
111
112 return true;
113}
114
115/* Initialize I/O specific objects */
116bool RadioInterfaceDiversity::init(int type)
117{
118 int tx_len, outer_rx_len;
119
120 if ((mMIMO != 2) || (mChans != 2)) {
121 LOG(ALERT) << "Unsupported channel configuration " << mChans;
122 return false;
123 }
124
125 /* Resize for channel combination */
126 sendBuffer.resize(mChans);
127 recvBuffer.resize(mChans * mMIMO);
128 convertSendBuffer.resize(mChans);
129 convertRecvBuffer.resize(mChans);
130 mReceiveFIFO.resize(mChans);
131 dnsamplers.resize(mChans * mMIMO);
132 phases.resize(mChans);
133
134 if (!setupDiversityChannels())
135 return false;
136
137 tx_len = CHUNK * mSPSTx;
138 outer_rx_len = resamp_outchunk;
139
140 for (size_t i = 0; i < mChans; i++) {
141 /* Full rate float and integer outer receive buffers */
142 convertRecvBuffer[i] = new short[outer_rx_len * 2];
143
144 /* Send buffers (not-resampled) */
145 sendBuffer[i] = new signalVector(tx_len);
146 convertSendBuffer[i] = new short[tx_len * 2];
147 }
148
149 outerRecvBuffer = new signalVector(outer_rx_len, dnsamplers[0]->len());
150
151 return true;
152}
153
154bool RadioInterfaceDiversity::tuneRx(double freq, size_t chan)
155{
156 double f0, f1;
157
158 if (chan > 1)
159 return false;
160
161 if (!mRadio->setRxFreq(freq, chan))
162 return false;
163
164 f0 = mRadio->getRxFreq(0);
165 f1 = mRadio->getRxFreq(1);
166
167 mFreqSpacing = f1 - f0;
168
169 if (abs(mFreqSpacing) <= 600e3)
170 mDiversity = true;
171 else
172 mDiversity = false;
173
174 return true;
175}
176
177/* Receive a timestamped chunk from the device */
178void RadioInterfaceDiversity::pullBuffer()
179{
180 bool local_underrun;
181 int rc, num, path0, path1;
182 signalVector *shift, *base;
183 float *in, *out, rate = -mFreqSpacing * 2.0 * M_PI / 1.08333333e6;
184
185 if (recvCursor > recvBuffer[0]->size() - resamp_inchunk)
186 return;
187
188 /* Outer buffer access size is fixed */
189 num = mRadio->readSamples(convertRecvBuffer,
190 resamp_outchunk,
191 &overrun,
192 readTimestamp,
193 &local_underrun);
194 if ((size_t) num != resamp_outchunk) {
195 LOG(ALERT) << "Receive error " << num;
196 return;
197 }
198
199 for (size_t i = 0; i < mChans; i++) {
200 convert_short_float((float *) outerRecvBuffer->begin(),
201 convertRecvBuffer[i], 2 * resamp_outchunk);
202
203 if (!i) {
204 path0 = 0;
205 path1 = 2;
206 } else {
207 path0 = 3;
208 path1 = 1;
209 }
210
211 /* Diversity path 1 */
212 base = outerRecvBuffer;
213 in = (float *) base->begin();
214 out = (float *) (recvBuffer[path0]->begin() + recvCursor);
215
216 rc = dnsamplers[2 * i + 0]->rotate(in, resamp_outchunk,
217 out, resamp_inchunk);
218 if (rc < 0) {
219 LOG(ALERT) << "Sample rate downsampling error";
220 }
221
222 /* Enable path 2 if Nyquist bandwidth is sufficient */
223 if (!mDiversity)
224 continue;
225
226 /* Diversity path 2 */
227 shift = new signalVector(base->size(), base->getStart());
228 in = (float *) shift->begin();
229 out = (float *) (recvBuffer[path1]->begin() + recvCursor);
230
231 rate = i ? -rate : rate;
232 if (!frequencyShift(shift, base, rate, phases[i], &phases[i])) {
233 LOG(ALERT) << "Frequency shift failed";
234 }
235
236 rc = dnsamplers[2 * i + 1]->rotate(in, resamp_outchunk,
237 out, resamp_inchunk);
238 if (rc < 0) {
239 LOG(ALERT) << "Sample rate downsampling error";
240 }
241
242 delete shift;
243 }
244
245 underrun |= local_underrun;
246 readTimestamp += (TIMESTAMP) resamp_outchunk;
247 recvCursor += resamp_inchunk;
248}