blob: b3973e55632f793e21ef7494568ac4d9d12cd336 [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;
Tom Tsou28670fb2015-08-21 19:32:58 -070068 delete dnsampler;
Thomas Tsoue90a42b2013-11-13 23:38:09 -050069
Tom Tsou28670fb2015-08-21 19:32:58 -070070 dnsampler = NULL;
Thomas Tsoue90a42b2013-11-13 23:38:09 -050071 outerRecvBuffer = NULL;
72
Thomas Tsoue90a42b2013-11-13 23:38:09 -050073 if (recvBuffer.size())
74 recvBuffer[0] = NULL;
75
76 RadioInterface::close();
77}
78
79bool RadioInterfaceDiversity::setupDiversityChannels()
80{
81 size_t inner_rx_len;
82
83 /* Inner and outer rates */
84 resamp_inrate = RESAMP_64M_INRATE;
85 resamp_outrate = RESAMP_64M_OUTRATE;
86 resamp_inchunk = resamp_inrate * 4;
87 resamp_outchunk = resamp_outrate * 4;
88
89 /* Buffer lengths */
90 inner_rx_len = NUMCHUNKS * resamp_inchunk;
91
92 /* Inside buffer must hold at least 2 bursts */
93 if (inner_rx_len < 157 * mSPSRx * 2) {
94 LOG(ALERT) << "Invalid inner buffer size " << inner_rx_len;
95 return false;
96 }
97
Tom Tsou28670fb2015-08-21 19:32:58 -070098 dnsampler = new Resampler(resamp_inrate, resamp_outrate);
99 if (!dnsampler->init()) {
100 LOG(ALERT) << "Rx resampler failed to initialize";
101 return false;
102 }
103
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500104 /* One Receive buffer and downsampler per diversity channel */
105 for (size_t i = 0; i < mMIMO * mChans; i++) {
Tom Tsou28670fb2015-08-21 19:32:58 -0700106 recvBuffer[i] = new RadioBuffer(NUMCHUNKS,
107 resamp_inchunk, 0, false);
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500108 }
109
110 return true;
111}
112
113/* Initialize I/O specific objects */
114bool RadioInterfaceDiversity::init(int type)
115{
Tom Tsou28670fb2015-08-21 19:32:58 -0700116 int outer_rx_len;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500117
118 if ((mMIMO != 2) || (mChans != 2)) {
119 LOG(ALERT) << "Unsupported channel configuration " << mChans;
120 return false;
121 }
122
123 /* Resize for channel combination */
124 sendBuffer.resize(mChans);
125 recvBuffer.resize(mChans * mMIMO);
126 convertSendBuffer.resize(mChans);
127 convertRecvBuffer.resize(mChans);
128 mReceiveFIFO.resize(mChans);
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500129 phases.resize(mChans);
130
131 if (!setupDiversityChannels())
132 return false;
133
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500134 outer_rx_len = resamp_outchunk;
135
136 for (size_t i = 0; i < mChans; i++) {
137 /* Full rate float and integer outer receive buffers */
138 convertRecvBuffer[i] = new short[outer_rx_len * 2];
139
140 /* Send buffers (not-resampled) */
Tom Tsou28670fb2015-08-21 19:32:58 -0700141 sendBuffer[i] = new RadioBuffer(NUMCHUNKS, CHUNK * mSPSTx, 0, true);
142 convertSendBuffer[i] = new short[CHUNK * mSPSTx * 2];
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500143 }
144
Tom Tsou28670fb2015-08-21 19:32:58 -0700145 outerRecvBuffer = new signalVector(outer_rx_len, dnsampler->len());
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500146
147 return true;
148}
149
150bool RadioInterfaceDiversity::tuneRx(double freq, size_t chan)
151{
152 double f0, f1;
153
154 if (chan > 1)
155 return false;
156
157 if (!mRadio->setRxFreq(freq, chan))
158 return false;
159
160 f0 = mRadio->getRxFreq(0);
161 f1 = mRadio->getRxFreq(1);
162
163 mFreqSpacing = f1 - f0;
164
165 if (abs(mFreqSpacing) <= 600e3)
166 mDiversity = true;
167 else
168 mDiversity = false;
169
170 return true;
171}
172
173/* Receive a timestamped chunk from the device */
174void RadioInterfaceDiversity::pullBuffer()
175{
176 bool local_underrun;
177 int rc, num, path0, path1;
178 signalVector *shift, *base;
179 float *in, *out, rate = -mFreqSpacing * 2.0 * M_PI / 1.08333333e6;
180
Tom Tsou28670fb2015-08-21 19:32:58 -0700181 if (recvBuffer[0]->getFreeSegments() <= 0)
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500182 return;
183
184 /* Outer buffer access size is fixed */
185 num = mRadio->readSamples(convertRecvBuffer,
186 resamp_outchunk,
187 &overrun,
188 readTimestamp,
189 &local_underrun);
190 if ((size_t) num != resamp_outchunk) {
191 LOG(ALERT) << "Receive error " << num;
192 return;
193 }
194
195 for (size_t i = 0; i < mChans; i++) {
196 convert_short_float((float *) outerRecvBuffer->begin(),
197 convertRecvBuffer[i], 2 * resamp_outchunk);
198
199 if (!i) {
200 path0 = 0;
201 path1 = 2;
202 } else {
203 path0 = 3;
204 path1 = 1;
205 }
206
207 /* Diversity path 1 */
208 base = outerRecvBuffer;
209 in = (float *) base->begin();
Tom Tsou28670fb2015-08-21 19:32:58 -0700210 out = (float *) recvBuffer[path0]->getWriteSegment();
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500211
Tom Tsou28670fb2015-08-21 19:32:58 -0700212 rc = dnsampler->rotate(in, resamp_outchunk,
213 out, resamp_inchunk);
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500214 if (rc < 0) {
215 LOG(ALERT) << "Sample rate downsampling error";
216 }
217
218 /* Enable path 2 if Nyquist bandwidth is sufficient */
219 if (!mDiversity)
220 continue;
221
222 /* Diversity path 2 */
223 shift = new signalVector(base->size(), base->getStart());
224 in = (float *) shift->begin();
Tom Tsou28670fb2015-08-21 19:32:58 -0700225 out = (float *) recvBuffer[path1]->getWriteSegment();
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500226
227 rate = i ? -rate : rate;
228 if (!frequencyShift(shift, base, rate, phases[i], &phases[i])) {
229 LOG(ALERT) << "Frequency shift failed";
230 }
231
Tom Tsou28670fb2015-08-21 19:32:58 -0700232 rc = dnsampler->rotate(in, resamp_outchunk,
233 out, resamp_inchunk);
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500234 if (rc < 0) {
235 LOG(ALERT) << "Sample rate downsampling error";
236 }
237
238 delete shift;
239 }
240
241 underrun |= local_underrun;
242 readTimestamp += (TIMESTAMP) resamp_outchunk;
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500243}