blob: 2b59203c0ff1ba7bb258cbe889014da9e92831f9 [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
kurtis.heimerlce317332011-11-26 03:18:39 +000031/* New chunk sizes for resampled rate */
32#ifdef INCHUNK
33 #undef INCHUNK
34#endif
35#ifdef OUTCHUNK
36 #undef OUTCHUNK
37#endif
38
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040039/* Resampling parameters for 100 MHz clocking */
40#define RESAMP_INRATE 52
41#define RESAMP_OUTRATE 75
42#define RESAMP_FILT_LEN 16
kurtis.heimerlce317332011-11-26 03:18:39 +000043
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040044#define INCHUNK (RESAMP_INRATE * 4)
45#define OUTCHUNK (RESAMP_OUTRATE * 4)
kurtis.heimerlce317332011-11-26 03:18:39 +000046
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040047static Resampler *upsampler = NULL;
48static Resampler *dnsampler = NULL;
49short *convertRecvBuffer = NULL;
50short *convertSendBuffer = NULL;
kurtis.heimerlce317332011-11-26 03:18:39 +000051
Thomas Tsoucb69f082013-04-08 14:18:26 -040052RadioInterfaceResamp::RadioInterfaceResamp(RadioDevice *wRadio,
53 int wReceiveOffset,
54 int wSPS,
55 GSM::Time wStartTime)
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040056 : RadioInterface(wRadio, wReceiveOffset, wSPS, wStartTime),
57 innerSendBuffer(NULL), outerSendBuffer(NULL),
58 innerRecvBuffer(NULL), outerRecvBuffer(NULL)
Thomas Tsoucb69f082013-04-08 14:18:26 -040059{
60}
61
Thomas Tsou03e6ecf2013-08-20 20:54:54 -040062RadioInterfaceResamp::~RadioInterfaceResamp()
63{
64 close();
65}
66
67void RadioInterfaceResamp::close()
68{
69 RadioInterface::close();
70
71 delete innerSendBuffer;
72 delete outerSendBuffer;
73 delete innerRecvBuffer;
74 delete outerRecvBuffer;
75
76 delete upsampler;
77 delete dnsampler;
78
79 innerSendBuffer = NULL;
80 outerSendBuffer = NULL;
81 innerRecvBuffer = NULL;
82 outerRecvBuffer = NULL;
83
84 upsampler = NULL;
85 dnsampler = NULL;
86}
87
88/* Initialize I/O specific objects */
89bool RadioInterfaceResamp::init()
90{
91 float cutoff = 1.0f;
92
93 close();
94
95 /*
96 * With oversampling, restrict bandwidth to 150% of base rate. This also
97 * provides last ditch bandwith limiting if the pulse shaping filter is
98 * insufficient.
99 */
100 if (sps > 1)
101 cutoff = 1.5 / sps;
102
103 dnsampler = new Resampler(RESAMP_INRATE, RESAMP_OUTRATE);
104 if (!dnsampler->init(cutoff)) {
105 LOG(ALERT) << "Rx resampler failed to initialize";
106 return false;
107 }
108
109 upsampler = new Resampler(RESAMP_OUTRATE, RESAMP_INRATE);
110 if (!upsampler->init(cutoff)) {
111 LOG(ALERT) << "Tx resampler failed to initialize";
112 return false;
113 }
114
115 /*
116 * Allocate high and low rate buffers. The high rate receive
117 * buffer and low rate transmit vectors feed into the resampler
118 * and requires headroom equivalent to the filter length. Low
119 * rate buffers are allocated in the main radio interface code.
120 */
121 innerSendBuffer = new signalVector(INCHUNK * 20, RESAMP_FILT_LEN);
122 outerSendBuffer = new signalVector(OUTCHUNK * 20);
123
124 outerRecvBuffer = new signalVector(OUTCHUNK * 2, RESAMP_FILT_LEN);
125 innerRecvBuffer = new signalVector(INCHUNK * 20);
126
127 convertSendBuffer = new short[OUTCHUNK * 2 * 20];
128 convertRecvBuffer = new short[OUTCHUNK * 2 * 2];
129
130 sendBuffer = innerSendBuffer;
131 recvBuffer = innerRecvBuffer;
132
133 return true;
134}
135
136/* Receive a timestamped chunk from the device */
Thomas Tsoucb69f082013-04-08 14:18:26 -0400137void RadioInterfaceResamp::pullBuffer()
kurtis.heimerlce317332011-11-26 03:18:39 +0000138{
kurtis.heimerlce317332011-11-26 03:18:39 +0000139 bool local_underrun;
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400140 int rc, num_recv;
141 int inner_len = INCHUNK;
142 int outer_len = OUTCHUNK;
kurtis.heimerlce317332011-11-26 03:18:39 +0000143
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400144 /* Outer buffer access size is fixed */
145 num_recv = mRadio->readSamples(convertRecvBuffer,
146 outer_len,
147 &overrun,
148 readTimestamp,
149 &local_underrun);
150 if (num_recv != outer_len) {
151 LOG(ALERT) << "Receive error " << num_recv;
152 return;
153 }
kurtis.heimerlce317332011-11-26 03:18:39 +0000154
Thomas Tsou9471d762013-08-20 21:24:24 -0400155 convert_short_float((float *) outerRecvBuffer->begin(),
156 convertRecvBuffer, 2 * outer_len);
kurtis.heimerlce317332011-11-26 03:18:39 +0000157
158 underrun |= local_underrun;
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400159 readTimestamp += (TIMESTAMP) num_recv;
kurtis.heimerlce317332011-11-26 03:18:39 +0000160
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400161 /* Write to the end of the inner receive buffer */
162 rc = dnsampler->rotate((float *) outerRecvBuffer->begin(), outer_len,
163 (float *) (innerRecvBuffer->begin() + recvCursor),
164 inner_len);
165 if (rc < 0) {
166 LOG(ALERT) << "Sample rate upsampling error";
167 }
kurtis.heimerlce317332011-11-26 03:18:39 +0000168
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400169 recvCursor += inner_len;
kurtis.heimerlce317332011-11-26 03:18:39 +0000170}
171
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400172/* Send a timestamped chunk to the device */
Thomas Tsoucb69f082013-04-08 14:18:26 -0400173void RadioInterfaceResamp::pushBuffer()
kurtis.heimerlce317332011-11-26 03:18:39 +0000174{
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400175 int rc, chunks, num_sent;
176 int inner_len, outer_len;
kurtis.heimerlce317332011-11-26 03:18:39 +0000177
178 if (sendCursor < INCHUNK)
179 return;
180
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400181 chunks = sendCursor / INCHUNK;
182 if (chunks > 8)
183 chunks = 8;
kurtis.heimerlce317332011-11-26 03:18:39 +0000184
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400185 inner_len = chunks * INCHUNK;
186 outer_len = chunks * OUTCHUNK;
kurtis.heimerlce317332011-11-26 03:18:39 +0000187
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400188 /* Always send from the beginning of the buffer */
189 rc = upsampler->rotate((float *) innerSendBuffer->begin(), inner_len,
190 (float *) outerSendBuffer->begin(), outer_len);
191 if (rc < 0) {
192 LOG(ALERT) << "Sample rate downsampling error";
193 }
kurtis.heimerlce317332011-11-26 03:18:39 +0000194
Thomas Tsou9471d762013-08-20 21:24:24 -0400195 convert_float_short(convertSendBuffer,
196 (float *) outerSendBuffer->begin(),
197 powerScaling, 2 * outer_len);
kurtis.heimerlce317332011-11-26 03:18:39 +0000198
Thomas Tsou03e6ecf2013-08-20 20:54:54 -0400199 num_sent = mRadio->writeSamples(convertSendBuffer,
200 outer_len,
201 &underrun,
202 writeTimestamp);
203 if (num_sent != outer_len) {
204 LOG(ALERT) << "Transmit error " << num_sent;
205 }
206
207 /* Shift remaining samples to beginning of buffer */
208 memmove(innerSendBuffer->begin(),
209 innerSendBuffer->begin() + inner_len,
210 (sendCursor - inner_len) * 2 * sizeof(float));
211
212 writeTimestamp += outer_len;
213 sendCursor -= inner_len;
214 assert(sendCursor >= 0);
kurtis.heimerlce317332011-11-26 03:18:39 +0000215}