blob: 26dd40be37706756146ae166673a6390921ad8db [file] [log] [blame]
kurtis.heimerlce317332011-11-26 03:18:39 +00001/*
2 * Radio device interface with sample rate conversion
kurtis.heimerlce317332011-11-26 03:18:39 +00003 *
Tom Tsou28670fb2015-08-21 19:32:58 -07004 * Copyright (C) 2011-2014 Free Software Foundation, Inc.
5 * Copyright (C) 2015 Ettus Research LLC
6 *
7 * Author: Tom Tsou <tom@tsou.cc>
kurtis.heimerlce317332011-11-26 03:18:39 +00008 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Affero General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Affero General Public License for more details.
18 *
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 * See the COPYING file in the main directory for details.
22 */
23
24#include <radioInterface.h>
25#include <Logger.h>
26
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040027#include "Resampler.h"
28
29extern "C" {
30#include "convert.h"
31}
32
Thomas Tsoufe269fe2013-10-14 23:56:51 -040033/* Resampling parameters for 64 MHz clocking */
34#define RESAMP_64M_INRATE 65
35#define RESAMP_64M_OUTRATE 96
36
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040037/* Resampling parameters for 100 MHz clocking */
Thomas Tsoufe269fe2013-10-14 23:56:51 -040038#define RESAMP_100M_INRATE 52
39#define RESAMP_100M_OUTRATE 75
Thomas Tsou0e44ab32013-09-17 20:12:26 -040040
Thomas Tsou3952d802013-10-15 15:12:24 -040041/* Universal resampling parameters */
42#define NUMCHUNKS 24
43
Thomas Tsou0e44ab32013-09-17 20:12:26 -040044/*
45 * Resampling filter bandwidth scaling factor
46 * This narrows the filter cutoff relative to the output bandwidth
47 * of the polyphase resampler. At 4 samples-per-symbol using the
48 * 2 pulse Laurent GMSK approximation gives us below 0.5 degrees
49 * RMS phase error at the resampler output.
50 */
51#define RESAMP_TX4_FILTER 0.45
kurtis.heimerlce317332011-11-26 03:18:39 +000052
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040053static Resampler *upsampler = NULL;
54static Resampler *dnsampler = NULL;
Thomas Tsoue90a42b2013-11-13 23:38:09 -050055static size_t resamp_inrate = 0;
56static size_t resamp_inchunk = 0;
57static size_t resamp_outrate = 0;
58static size_t resamp_outchunk = 0;
Thomas Tsoufe269fe2013-10-14 23:56:51 -040059
Thomas Tsoucb69f082013-04-08 14:18:26 -040060RadioInterfaceResamp::RadioInterfaceResamp(RadioDevice *wRadio,
Thomas Tsoue90a42b2013-11-13 23:38:09 -050061 size_t sps, size_t chans)
62 : RadioInterface(wRadio, sps, chans),
Tom Tsou28670fb2015-08-21 19:32:58 -070063 outerSendBuffer(NULL),
64 outerRecvBuffer(NULL)
Thomas Tsoucb69f082013-04-08 14:18:26 -040065{
66}
67
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040068RadioInterfaceResamp::~RadioInterfaceResamp()
69{
70 close();
71}
72
73void RadioInterfaceResamp::close()
74{
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040075 delete outerSendBuffer;
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040076 delete outerRecvBuffer;
77
78 delete upsampler;
79 delete dnsampler;
80
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040081 outerSendBuffer = NULL;
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040082 outerRecvBuffer = NULL;
83
84 upsampler = NULL;
85 dnsampler = NULL;
Thomas Tsoude1648c2013-10-15 16:18:58 -040086
Thomas Tsou204a9f12013-10-29 18:34:16 -040087 if (sendBuffer.size())
88 sendBuffer[0] = NULL;
89 if (recvBuffer.size())
90 recvBuffer[0] = NULL;
91
Thomas Tsoude1648c2013-10-15 16:18:58 -040092 RadioInterface::close();
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040093}
94
95/* Initialize I/O specific objects */
Thomas Tsoufe269fe2013-10-14 23:56:51 -040096bool RadioInterfaceResamp::init(int type)
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040097{
98 float cutoff = 1.0f;
99
Thomas Tsou204a9f12013-10-29 18:34:16 -0400100 if (mChans != 1) {
101 LOG(ALERT) << "Unsupported channel configuration " << mChans;
102 return false;
103 }
104
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400105 close();
106
Thomas Tsou204a9f12013-10-29 18:34:16 -0400107 sendBuffer.resize(1);
108 recvBuffer.resize(1);
109 convertSendBuffer.resize(1);
110 convertRecvBuffer.resize(1);
111 mReceiveFIFO.resize(1);
Thomas Tsouaf506442013-11-18 01:35:22 -0500112 powerScaling.resize(1);
Thomas Tsou204a9f12013-10-29 18:34:16 -0400113
Thomas Tsoufe269fe2013-10-14 23:56:51 -0400114 switch (type) {
115 case RadioDevice::RESAMP_64M:
116 resamp_inrate = RESAMP_64M_INRATE;
117 resamp_outrate = RESAMP_64M_OUTRATE;
118 break;
119 case RadioDevice::RESAMP_100M:
120 resamp_inrate = RESAMP_100M_INRATE;
121 resamp_outrate = RESAMP_100M_OUTRATE;
122 break;
123 case RadioDevice::NORMAL:
124 default:
125 LOG(ALERT) << "Invalid device configuration";
126 return false;
127 }
128
129 resamp_inchunk = resamp_inrate * 4;
130 resamp_outchunk = resamp_outrate * 4;
131
Thomas Tsou3952d802013-10-15 15:12:24 -0400132 if (resamp_inchunk * NUMCHUNKS < 157 * mSPSTx * 2) {
133 LOG(ALERT) << "Invalid inner chunk size " << resamp_inchunk;
134 return false;
135 }
136
Thomas Tsou0e44ab32013-09-17 20:12:26 -0400137 if (mSPSTx == 4)
138 cutoff = RESAMP_TX4_FILTER;
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400139
Thomas Tsoufe269fe2013-10-14 23:56:51 -0400140 dnsampler = new Resampler(resamp_inrate, resamp_outrate);
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400141 if (!dnsampler->init()) {
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400142 LOG(ALERT) << "Rx resampler failed to initialize";
143 return false;
144 }
145
Thomas Tsoufe269fe2013-10-14 23:56:51 -0400146 upsampler = new Resampler(resamp_outrate, resamp_inrate);
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400147 if (!upsampler->init(cutoff)) {
148 LOG(ALERT) << "Tx resampler failed to initialize";
149 return false;
150 }
151
152 /*
153 * Allocate high and low rate buffers. The high rate receive
154 * buffer and low rate transmit vectors feed into the resampler
155 * and requires headroom equivalent to the filter length. Low
156 * rate buffers are allocated in the main radio interface code.
157 */
Tom Tsou28670fb2015-08-21 19:32:58 -0700158 sendBuffer[0] = new RadioBuffer(NUMCHUNKS, resamp_inchunk,
159 upsampler->len(), true);
160 recvBuffer[0] = new RadioBuffer(NUMCHUNKS * 20, resamp_inchunk, 0, false);
161
Thomas Tsou3952d802013-10-15 15:12:24 -0400162 outerSendBuffer =
163 new signalVector(NUMCHUNKS * resamp_outchunk);
164 outerRecvBuffer =
165 new signalVector(resamp_outchunk, dnsampler->len());
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400166
Thomas Tsou204a9f12013-10-29 18:34:16 -0400167 convertSendBuffer[0] = new short[outerSendBuffer->size() * 2];
168 convertRecvBuffer[0] = new short[outerRecvBuffer->size() * 2];
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400169
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400170 return true;
171}
172
173/* Receive a timestamped chunk from the device */
Thomas Tsoucb69f082013-04-08 14:18:26 -0400174void RadioInterfaceResamp::pullBuffer()
kurtis.heimerlce317332011-11-26 03:18:39 +0000175{
kurtis.heimerlce317332011-11-26 03:18:39 +0000176 bool local_underrun;
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400177 int rc, num_recv;
Thomas Tsou3952d802013-10-15 15:12:24 -0400178
Tom Tsou28670fb2015-08-21 19:32:58 -0700179 if (recvBuffer[0]->getFreeSegments() <= 0)
Thomas Tsou3952d802013-10-15 15:12:24 -0400180 return;
kurtis.heimerlce317332011-11-26 03:18:39 +0000181
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400182 /* Outer buffer access size is fixed */
183 num_recv = mRadio->readSamples(convertRecvBuffer,
Thomas Tsou3952d802013-10-15 15:12:24 -0400184 resamp_outchunk,
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400185 &overrun,
186 readTimestamp,
187 &local_underrun);
Thomas Tsoue90a42b2013-11-13 23:38:09 -0500188 if (num_recv != (int) resamp_outchunk) {
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400189 LOG(ALERT) << "Receive error " << num_recv;
190 return;
191 }
kurtis.heimerlce317332011-11-26 03:18:39 +0000192
Thomas Tsou9471d762013-08-20 21:24:24 -0400193 convert_short_float((float *) outerRecvBuffer->begin(),
Thomas Tsou204a9f12013-10-29 18:34:16 -0400194 convertRecvBuffer[0], 2 * resamp_outchunk);
kurtis.heimerlce317332011-11-26 03:18:39 +0000195
196 underrun |= local_underrun;
Thomas Tsou3952d802013-10-15 15:12:24 -0400197 readTimestamp += (TIMESTAMP) resamp_outchunk;
kurtis.heimerlce317332011-11-26 03:18:39 +0000198
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400199 /* Write to the end of the inner receive buffer */
Thomas Tsou3952d802013-10-15 15:12:24 -0400200 rc = dnsampler->rotate((float *) outerRecvBuffer->begin(),
201 resamp_outchunk,
Tom Tsou28670fb2015-08-21 19:32:58 -0700202 recvBuffer[0]->getWriteSegment(),
Thomas Tsou3952d802013-10-15 15:12:24 -0400203 resamp_inchunk);
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400204 if (rc < 0) {
205 LOG(ALERT) << "Sample rate upsampling error";
206 }
kurtis.heimerlce317332011-11-26 03:18:39 +0000207
Tom Tsou28670fb2015-08-21 19:32:58 -0700208 /* Set history for the next chunk */
209 outerRecvBuffer->updateHistory();
kurtis.heimerlce317332011-11-26 03:18:39 +0000210}
211
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400212/* Send a timestamped chunk to the device */
Tom Tsou28670fb2015-08-21 19:32:58 -0700213bool RadioInterfaceResamp::pushBuffer()
kurtis.heimerlce317332011-11-26 03:18:39 +0000214{
Tom Tsou28670fb2015-08-21 19:32:58 -0700215 int rc;
216 size_t numSent;
kurtis.heimerlce317332011-11-26 03:18:39 +0000217
Tom Tsou28670fb2015-08-21 19:32:58 -0700218 if (sendBuffer[0]->getAvailSegments() <= 0)
219 return false;
kurtis.heimerlce317332011-11-26 03:18:39 +0000220
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400221 /* Always send from the beginning of the buffer */
Tom Tsou28670fb2015-08-21 19:32:58 -0700222 rc = upsampler->rotate(sendBuffer[0]->getReadSegment(),
223 resamp_inchunk,
224 (float *) outerSendBuffer->begin(),
225 resamp_outchunk);
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400226 if (rc < 0) {
227 LOG(ALERT) << "Sample rate downsampling error";
228 }
kurtis.heimerlce317332011-11-26 03:18:39 +0000229
Thomas Tsou204a9f12013-10-29 18:34:16 -0400230 convert_float_short(convertSendBuffer[0],
Thomas Tsou9471d762013-08-20 21:24:24 -0400231 (float *) outerSendBuffer->begin(),
Tom Tsou28670fb2015-08-21 19:32:58 -0700232 powerScaling[0], 2 * resamp_outchunk);
kurtis.heimerlce317332011-11-26 03:18:39 +0000233
Tom Tsou28670fb2015-08-21 19:32:58 -0700234 numSent = mRadio->writeSamples(convertSendBuffer,
235 resamp_outchunk,
236 &underrun,
237 writeTimestamp);
238 if (numSent != resamp_outchunk) {
239 LOG(ALERT) << "Transmit error " << numSent;
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400240 }
241
Tom Tsou28670fb2015-08-21 19:32:58 -0700242 writeTimestamp += resamp_outchunk;
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400243
Tom Tsou28670fb2015-08-21 19:32:58 -0700244 return true;
kurtis.heimerlce317332011-11-26 03:18:39 +0000245}