blob: f857df9429de2620696f108e5874bb33d8136325 [file] [log] [blame]
kurtis.heimerlce317332011-11-26 03:18:39 +00001/*
2 * Radio device interface with sample rate conversion
Thomas Tsou03e6ecf2013-08-20 20:54:54 -04003 * Written by Thomas Tsou <tom@tsou.cc>
kurtis.heimerlce317332011-11-26 03:18:39 +00004 *
Thomas Tsou03e6ecf2013-08-20 20:54:54 -04005 * Copyright 2011, 2012, 2013 Free Software Foundation, Inc.
kurtis.heimerlce317332011-11-26 03:18:39 +00006 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program 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 Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * See the COPYING file in the main directory for details.
20 */
21
22#include <radioInterface.h>
23#include <Logger.h>
24
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040025#include "Resampler.h"
26
27extern "C" {
28#include "convert.h"
29}
30
Thomas Tsoufe269fe2013-10-14 23:56:51 -040031/* Resampling parameters for 64 MHz clocking */
32#define RESAMP_64M_INRATE 65
33#define RESAMP_64M_OUTRATE 96
34
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040035/* Resampling parameters for 100 MHz clocking */
Thomas Tsoufe269fe2013-10-14 23:56:51 -040036#define RESAMP_100M_INRATE 52
37#define RESAMP_100M_OUTRATE 75
Thomas Tsou0e44ab32013-09-17 20:12:26 -040038
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
kurtis.heimerlce317332011-11-26 03:18:39 +000047
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040048static Resampler *upsampler = NULL;
49static Resampler *dnsampler = NULL;
Thomas Tsoufe269fe2013-10-14 23:56:51 -040050static int resamp_inrate = 0;
51static int resamp_inchunk = 0;
52static int resamp_outrate = 0;
53static int resamp_outchunk = 0;
54
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040055short *convertRecvBuffer = NULL;
56short *convertSendBuffer = NULL;
kurtis.heimerlce317332011-11-26 03:18:39 +000057
Thomas Tsoucb69f082013-04-08 14:18:26 -040058RadioInterfaceResamp::RadioInterfaceResamp(RadioDevice *wRadio,
59 int wReceiveOffset,
60 int wSPS,
61 GSM::Time wStartTime)
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040062 : RadioInterface(wRadio, wReceiveOffset, wSPS, wStartTime),
63 innerSendBuffer(NULL), outerSendBuffer(NULL),
64 innerRecvBuffer(NULL), 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{
75 RadioInterface::close();
76
77 delete innerSendBuffer;
78 delete outerSendBuffer;
79 delete innerRecvBuffer;
80 delete outerRecvBuffer;
81
82 delete upsampler;
83 delete dnsampler;
84
85 innerSendBuffer = NULL;
86 outerSendBuffer = NULL;
87 innerRecvBuffer = NULL;
88 outerRecvBuffer = NULL;
89
90 upsampler = NULL;
91 dnsampler = NULL;
92}
93
94/* Initialize I/O specific objects */
Thomas Tsoufe269fe2013-10-14 23:56:51 -040095bool RadioInterfaceResamp::init(int type)
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040096{
97 float cutoff = 1.0f;
98
99 close();
100
Thomas Tsoufe269fe2013-10-14 23:56:51 -0400101 switch (type) {
102 case RadioDevice::RESAMP_64M:
103 resamp_inrate = RESAMP_64M_INRATE;
104 resamp_outrate = RESAMP_64M_OUTRATE;
105 break;
106 case RadioDevice::RESAMP_100M:
107 resamp_inrate = RESAMP_100M_INRATE;
108 resamp_outrate = RESAMP_100M_OUTRATE;
109 break;
110 case RadioDevice::NORMAL:
111 default:
112 LOG(ALERT) << "Invalid device configuration";
113 return false;
114 }
115
116 resamp_inchunk = resamp_inrate * 4;
117 resamp_outchunk = resamp_outrate * 4;
118
Thomas Tsou0e44ab32013-09-17 20:12:26 -0400119 if (mSPSTx == 4)
120 cutoff = RESAMP_TX4_FILTER;
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400121
Thomas Tsoufe269fe2013-10-14 23:56:51 -0400122 dnsampler = new Resampler(resamp_inrate, resamp_outrate);
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400123 if (!dnsampler->init()) {
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400124 LOG(ALERT) << "Rx resampler failed to initialize";
125 return false;
126 }
127
Thomas Tsoufe269fe2013-10-14 23:56:51 -0400128 upsampler = new Resampler(resamp_outrate, resamp_inrate);
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400129 if (!upsampler->init(cutoff)) {
130 LOG(ALERT) << "Tx resampler failed to initialize";
131 return false;
132 }
133
134 /*
135 * Allocate high and low rate buffers. The high rate receive
136 * buffer and low rate transmit vectors feed into the resampler
137 * and requires headroom equivalent to the filter length. Low
138 * rate buffers are allocated in the main radio interface code.
139 */
Thomas Tsoufe269fe2013-10-14 23:56:51 -0400140 innerSendBuffer = new signalVector(resamp_inchunk * 20,
141 upsampler->len());
142 outerSendBuffer = new signalVector(resamp_outchunk * 20);
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400143
Thomas Tsoufe269fe2013-10-14 23:56:51 -0400144 outerRecvBuffer = new signalVector(resamp_outchunk * 2,
145 dnsampler->len());
146 innerRecvBuffer = new signalVector(resamp_inchunk * 20);
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400147
Thomas Tsoufe269fe2013-10-14 23:56:51 -0400148 convertSendBuffer = new short[resamp_outchunk * 2 * 20];
149 convertRecvBuffer = new short[resamp_outchunk * 2 * 2];
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400150
151 sendBuffer = innerSendBuffer;
152 recvBuffer = innerRecvBuffer;
153
154 return true;
155}
156
157/* Receive a timestamped chunk from the device */
Thomas Tsoucb69f082013-04-08 14:18:26 -0400158void RadioInterfaceResamp::pullBuffer()
kurtis.heimerlce317332011-11-26 03:18:39 +0000159{
kurtis.heimerlce317332011-11-26 03:18:39 +0000160 bool local_underrun;
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400161 int rc, num_recv;
Thomas Tsoufe269fe2013-10-14 23:56:51 -0400162 int inner_len = resamp_inchunk;
163 int outer_len = resamp_outchunk;
kurtis.heimerlce317332011-11-26 03:18:39 +0000164
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400165 /* Outer buffer access size is fixed */
166 num_recv = mRadio->readSamples(convertRecvBuffer,
167 outer_len,
168 &overrun,
169 readTimestamp,
170 &local_underrun);
171 if (num_recv != outer_len) {
172 LOG(ALERT) << "Receive error " << num_recv;
173 return;
174 }
kurtis.heimerlce317332011-11-26 03:18:39 +0000175
Thomas Tsou9471d762013-08-20 21:24:24 -0400176 convert_short_float((float *) outerRecvBuffer->begin(),
177 convertRecvBuffer, 2 * outer_len);
kurtis.heimerlce317332011-11-26 03:18:39 +0000178
179 underrun |= local_underrun;
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400180 readTimestamp += (TIMESTAMP) num_recv;
kurtis.heimerlce317332011-11-26 03:18:39 +0000181
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400182 /* Write to the end of the inner receive buffer */
183 rc = dnsampler->rotate((float *) outerRecvBuffer->begin(), outer_len,
184 (float *) (innerRecvBuffer->begin() + recvCursor),
185 inner_len);
186 if (rc < 0) {
187 LOG(ALERT) << "Sample rate upsampling error";
188 }
kurtis.heimerlce317332011-11-26 03:18:39 +0000189
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400190 recvCursor += inner_len;
kurtis.heimerlce317332011-11-26 03:18:39 +0000191}
192
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400193/* Send a timestamped chunk to the device */
Thomas Tsoucb69f082013-04-08 14:18:26 -0400194void RadioInterfaceResamp::pushBuffer()
kurtis.heimerlce317332011-11-26 03:18:39 +0000195{
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400196 int rc, chunks, num_sent;
197 int inner_len, outer_len;
kurtis.heimerlce317332011-11-26 03:18:39 +0000198
Thomas Tsoufe269fe2013-10-14 23:56:51 -0400199 if (sendCursor < resamp_inchunk)
kurtis.heimerlce317332011-11-26 03:18:39 +0000200 return;
201
Thomas Tsoufe269fe2013-10-14 23:56:51 -0400202 chunks = sendCursor / resamp_inchunk;
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400203 if (chunks > 8)
204 chunks = 8;
kurtis.heimerlce317332011-11-26 03:18:39 +0000205
Thomas Tsoufe269fe2013-10-14 23:56:51 -0400206 inner_len = chunks * resamp_inchunk;
207 outer_len = chunks * resamp_outchunk;
kurtis.heimerlce317332011-11-26 03:18:39 +0000208
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400209 /* Always send from the beginning of the buffer */
210 rc = upsampler->rotate((float *) innerSendBuffer->begin(), inner_len,
211 (float *) outerSendBuffer->begin(), outer_len);
212 if (rc < 0) {
213 LOG(ALERT) << "Sample rate downsampling error";
214 }
kurtis.heimerlce317332011-11-26 03:18:39 +0000215
Thomas Tsou9471d762013-08-20 21:24:24 -0400216 convert_float_short(convertSendBuffer,
217 (float *) outerSendBuffer->begin(),
218 powerScaling, 2 * outer_len);
kurtis.heimerlce317332011-11-26 03:18:39 +0000219
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400220 num_sent = mRadio->writeSamples(convertSendBuffer,
221 outer_len,
222 &underrun,
223 writeTimestamp);
224 if (num_sent != outer_len) {
225 LOG(ALERT) << "Transmit error " << num_sent;
226 }
227
228 /* Shift remaining samples to beginning of buffer */
229 memmove(innerSendBuffer->begin(),
230 innerSendBuffer->begin() + inner_len,
231 (sendCursor - inner_len) * 2 * sizeof(float));
232
233 writeTimestamp += outer_len;
234 sendCursor -= inner_len;
235 assert(sendCursor >= 0);
kurtis.heimerlce317332011-11-26 03:18:39 +0000236}