comparison spandsp-0.0.6pre17/src/v29tx.c @ 4:26cd8f1ef0b1

import spandsp-0.0.6pre17
author Peter Meerwald <pmeerw@cosy.sbg.ac.at>
date Fri, 25 Jun 2010 15:50:58 +0200
parents
children
comparison
equal deleted inserted replaced
3:c6c5a16ce2f2 4:26cd8f1ef0b1
1 /*
2 * SpanDSP - a series of DSP components for telephony
3 *
4 * v29tx.c - ITU V.29 modem transmit part
5 *
6 * Written by Steve Underwood <steveu@coppice.org>
7 *
8 * Copyright (C) 2003 Steve Underwood
9 *
10 * All rights reserved.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 2.1,
14 * as published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 * $Id: v29tx.c,v 1.89 2009/06/02 16:03:56 steveu Exp $
26 */
27
28 /*! \file */
29
30 #if defined(HAVE_CONFIG_H)
31 #include "config.h"
32 #endif
33
34 #include <stdio.h>
35 #include <inttypes.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #if defined(HAVE_TGMATH_H)
39 #include <tgmath.h>
40 #endif
41 #if defined(HAVE_MATH_H)
42 #include <math.h>
43 #endif
44 #include "floating_fudge.h"
45
46 #include "spandsp/telephony.h"
47 #include "spandsp/fast_convert.h"
48 #include "spandsp/logging.h"
49 #include "spandsp/complex.h"
50 #include "spandsp/vector_float.h"
51 #include "spandsp/complex_vector_float.h"
52 #include "spandsp/async.h"
53 #include "spandsp/dds.h"
54 #include "spandsp/power_meter.h"
55
56 #include "spandsp/v29tx.h"
57
58 #include "spandsp/private/logging.h"
59 #include "spandsp/private/v29tx.h"
60
61 #include "v29tx_constellation_maps.h"
62 #if defined(SPANDSP_USE_FIXED_POINT)
63 #include "v29tx_fixed_rrc.h"
64 #else
65 #include "v29tx_floating_rrc.h"
66 #endif
67
68 /*! The nominal frequency of the carrier, in Hertz */
69 #define CARRIER_NOMINAL_FREQ 1700.0f
70
71 /* Segments of the training sequence */
72 /*! The start of the optional TEP, that may preceed the actual training, in symbols */
73 #define V29_TRAINING_SEG_TEP 0
74 /*! The start of training segment 1, in symbols */
75 #define V29_TRAINING_SEG_1 (V29_TRAINING_SEG_TEP + 480)
76 /*! The start of training segment 2, in symbols */
77 #define V29_TRAINING_SEG_2 (V29_TRAINING_SEG_1 + 48)
78 /*! The start of training segment 3, in symbols */
79 #define V29_TRAINING_SEG_3 (V29_TRAINING_SEG_2 + 128)
80 /*! The start of training segment 4, in symbols */
81 #define V29_TRAINING_SEG_4 (V29_TRAINING_SEG_3 + 384)
82 /*! The end of the training, in symbols */
83 #define V29_TRAINING_END (V29_TRAINING_SEG_4 + 48)
84 /*! The end of the shutdown sequence, in symbols */
85 #define V29_TRAINING_SHUTDOWN_END (V29_TRAINING_END + 32)
86
87 static int fake_get_bit(void *user_data)
88 {
89 return 1;
90 }
91 /*- End of function --------------------------------------------------------*/
92
93 static __inline__ int get_scrambled_bit(v29_tx_state_t *s)
94 {
95 int bit;
96 int out_bit;
97
98 if ((bit = s->current_get_bit(s->get_bit_user_data)) == SIG_STATUS_END_OF_DATA)
99 {
100 /* End of real data. Switch to the fake get_bit routine, until we
101 have shut down completely. */
102 if (s->status_handler)
103 s->status_handler(s->status_user_data, SIG_STATUS_END_OF_DATA);
104 s->current_get_bit = fake_get_bit;
105 s->in_training = TRUE;
106 bit = 1;
107 }
108 out_bit = (bit ^ (s->scramble_reg >> 17) ^ (s->scramble_reg >> 22)) & 1;
109 s->scramble_reg = (s->scramble_reg << 1) | out_bit;
110 return out_bit;
111 }
112 /*- End of function --------------------------------------------------------*/
113
114 #if defined(SPANDSP_USE_FIXED_POINT)
115 static __inline__ complexi16_t getbaud(v29_tx_state_t *s)
116 #else
117 static __inline__ complexf_t getbaud(v29_tx_state_t *s)
118 #endif
119 {
120 static const int phase_steps_9600[8] =
121 {
122 1, 0, 2, 3, 6, 7, 5, 4
123 };
124 static const int phase_steps_4800[4] =
125 {
126 0, 2, 6, 4
127 };
128 #if defined(SPANDSP_USE_FIXED_POINT)
129 static const complexi16_t zero = {0, 0};
130 #else
131 static const complexf_t zero = {0.0f, 0.0f};
132 #endif
133 int bits;
134 int amp;
135 int bit;
136
137 if (s->in_training)
138 {
139 /* Send the training sequence */
140 if (++s->training_step <= V29_TRAINING_SEG_4)
141 {
142 if (s->training_step <= V29_TRAINING_SEG_3)
143 {
144 if (s->training_step <= V29_TRAINING_SEG_1)
145 {
146 /* Optional segment: Unmodulated carrier (talker echo protection) */
147 return v29_9600_constellation[0];
148 }
149 if (s->training_step <= V29_TRAINING_SEG_2)
150 {
151 /* Segment 1: silence */
152 return zero;
153 }
154 /* Segment 2: ABAB... */
155 return v29_abab_constellation[(s->training_step & 1) + s->training_offset];
156 }
157 /* Segment 3: CDCD... */
158 /* Apply the 1 + x^-6 + x^-7 training scrambler */
159 bit = s->training_scramble_reg & 1;
160 s->training_scramble_reg >>= 1;
161 s->training_scramble_reg |= (((bit ^ s->training_scramble_reg) & 1) << 6);
162 return v29_cdcd_constellation[bit + s->training_offset];
163 }
164 /* We should be in the block of test ones, or shutdown ones, if we get here. */
165 /* There is no graceful shutdown procedure defined for V.29. Just
166 send some ones, to ensure we get the real data bits through, even
167 with bad ISI. */
168 if (s->training_step == V29_TRAINING_END + 1)
169 {
170 /* Switch from the fake get_bit routine, to the user supplied real
171 one, and we are up and running. */
172 s->current_get_bit = s->get_bit;
173 s->in_training = FALSE;
174 }
175 if (s->training_step == V29_TRAINING_SHUTDOWN_END)
176 {
177 if (s->status_handler)
178 s->status_handler(s->status_user_data, SIG_STATUS_SHUTDOWN_COMPLETE);
179 }
180 }
181 /* 9600bps uses the full constellation.
182 7200bps uses only the first half of the full constellation.
183 4800bps uses the smaller constellation. */
184 amp = 0;
185 /* We only use an amplitude bit at 9600bps */
186 if (s->bit_rate == 9600 && get_scrambled_bit(s))
187 amp = 8;
188 /*endif*/
189 bits = get_scrambled_bit(s);
190 bits = (bits << 1) | get_scrambled_bit(s);
191 if (s->bit_rate == 4800)
192 {
193 bits = phase_steps_4800[bits];
194 }
195 else
196 {
197 bits = (bits << 1) | get_scrambled_bit(s);
198 bits = phase_steps_9600[bits];
199 }
200 s->constellation_state = (s->constellation_state + bits) & 7;
201 return v29_9600_constellation[amp | s->constellation_state];
202 }
203 /*- End of function --------------------------------------------------------*/
204
205 SPAN_DECLARE_NONSTD(int) v29_tx(v29_tx_state_t *s, int16_t amp[], int len)
206 {
207 #if defined(SPANDSP_USE_FIXED_POINT)
208 complexi_t x;
209 complexi_t z;
210 #else
211 complexf_t x;
212 complexf_t z;
213 #endif
214 int i;
215 int sample;
216
217 if (s->training_step >= V29_TRAINING_SHUTDOWN_END)
218 {
219 /* Once we have sent the shutdown symbols, we stop sending completely. */
220 return 0;
221 }
222 for (sample = 0; sample < len; sample++)
223 {
224 if ((s->baud_phase += 3) >= 10)
225 {
226 s->baud_phase -= 10;
227 s->rrc_filter[s->rrc_filter_step] =
228 s->rrc_filter[s->rrc_filter_step + V29_TX_FILTER_STEPS] = getbaud(s);
229 if (++s->rrc_filter_step >= V29_TX_FILTER_STEPS)
230 s->rrc_filter_step = 0;
231 }
232 /* Root raised cosine pulse shaping at baseband */
233 #if defined(SPANDSP_USE_FIXED_POINT)
234 x = complex_seti(0, 0);
235 for (i = 0; i < V29_TX_FILTER_STEPS; i++)
236 {
237 x.re += (int32_t) tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase][i]*(int32_t) s->rrc_filter[i + s->rrc_filter_step].re;
238 x.im += (int32_t) tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase][i]*(int32_t) s->rrc_filter[i + s->rrc_filter_step].im;
239 }
240 /* Now create and modulate the carrier */
241 x.re >>= 4;
242 x.im >>= 4;
243 z = dds_complexi(&(s->carrier_phase), s->carrier_phase_rate);
244 /* Don't bother saturating. We should never clip. */
245 i = (x.re*z.re - x.im*z.im) >> 15;
246 amp[sample] = (int16_t) ((i*s->gain) >> 15);
247 #else
248 x = complex_setf(0.0f, 0.0f);
249 for (i = 0; i < V29_TX_FILTER_STEPS; i++)
250 {
251 x.re += tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase][i]*s->rrc_filter[i + s->rrc_filter_step].re;
252 x.im += tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase][i]*s->rrc_filter[i + s->rrc_filter_step].im;
253 }
254 /* Now create and modulate the carrier */
255 z = dds_complexf(&(s->carrier_phase), s->carrier_phase_rate);
256 /* Don't bother saturating. We should never clip. */
257 amp[sample] = (int16_t) lfastrintf((x.re*z.re - x.im*z.im)*s->gain);
258 #endif
259 }
260 return sample;
261 }
262 /*- End of function --------------------------------------------------------*/
263
264 static void set_working_gain(v29_tx_state_t *s)
265 {
266 #if defined(SPANDSP_USE_FIXED_POINT)
267 switch (s->bit_rate)
268 {
269 case 9600:
270 s->gain = 0.387f*s->base_gain*16.0f*32767.0f/30672.52f;
271 break;
272 case 7200:
273 s->gain = 0.605f*s->base_gain*16.0f*32767.0f/30672.52f;
274 break;
275 case 4800:
276 s->gain = 0.470f*s->base_gain*16.0f*32767.0f/30672.52f;
277 break;
278 default:
279 break;
280 }
281 #else
282 switch (s->bit_rate)
283 {
284 case 9600:
285 s->gain = 0.387f*s->base_gain;
286 break;
287 case 7200:
288 s->gain = 0.605f*s->base_gain;
289 break;
290 case 4800:
291 s->gain = 0.470f*s->base_gain;
292 break;
293 default:
294 break;
295 }
296 #endif
297 }
298 /*- End of function --------------------------------------------------------*/
299
300 SPAN_DECLARE(void) v29_tx_power(v29_tx_state_t *s, float power)
301 {
302 /* The constellation does not maintain constant average power as we change bit rates.
303 We need to scale the gain we get here by a bit rate specific scaling factor each
304 time we restart the modem. */
305 s->base_gain = powf(10.0f, (power - DBM0_MAX_POWER)/20.0f)*32768.0f/TX_PULSESHAPER_GAIN;
306 set_working_gain(s);
307 }
308 /*- End of function --------------------------------------------------------*/
309
310 SPAN_DECLARE(void) v29_tx_set_get_bit(v29_tx_state_t *s, get_bit_func_t get_bit, void *user_data)
311 {
312 if (s->get_bit == s->current_get_bit)
313 s->current_get_bit = get_bit;
314 s->get_bit = get_bit;
315 s->get_bit_user_data = user_data;
316 }
317 /*- End of function --------------------------------------------------------*/
318
319 SPAN_DECLARE(void) v29_tx_set_modem_status_handler(v29_tx_state_t *s, modem_tx_status_func_t handler, void *user_data)
320 {
321 s->status_handler = handler;
322 s->status_user_data = user_data;
323 }
324 /*- End of function --------------------------------------------------------*/
325
326 SPAN_DECLARE(logging_state_t *) v29_tx_get_logging_state(v29_tx_state_t *s)
327 {
328 return &s->logging;
329 }
330 /*- End of function --------------------------------------------------------*/
331
332 SPAN_DECLARE(int) v29_tx_restart(v29_tx_state_t *s, int bit_rate, int tep)
333 {
334 span_log(&s->logging, SPAN_LOG_FLOW, "Restarting V.29\n");
335 s->bit_rate = bit_rate;
336 set_working_gain(s);
337 switch (s->bit_rate)
338 {
339 case 9600:
340 s->training_offset = 0;
341 break;
342 case 7200:
343 s->training_offset = 2;
344 break;
345 case 4800:
346 s->training_offset = 4;
347 break;
348 default:
349 return -1;
350 }
351 #if defined(SPANDSP_USE_FIXED_POINT)
352 memset(s->rrc_filter, 0, sizeof(s->rrc_filter));
353 #else
354 cvec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
355 #endif
356 s->rrc_filter_step = 0;
357 s->scramble_reg = 0;
358 s->training_scramble_reg = 0x2A;
359 s->in_training = TRUE;
360 s->training_step = (tep) ? V29_TRAINING_SEG_TEP : V29_TRAINING_SEG_1;
361 s->carrier_phase = 0;
362 s->baud_phase = 0;
363 s->constellation_state = 0;
364 s->current_get_bit = fake_get_bit;
365 return 0;
366 }
367 /*- End of function --------------------------------------------------------*/
368
369 SPAN_DECLARE(v29_tx_state_t *) v29_tx_init(v29_tx_state_t *s, int bit_rate, int tep, get_bit_func_t get_bit, void *user_data)
370 {
371 switch (bit_rate)
372 {
373 case 9600:
374 case 7200:
375 case 4800:
376 break;
377 default:
378 return NULL;
379 }
380 if (s == NULL)
381 {
382 if ((s = (v29_tx_state_t *) malloc(sizeof(*s))) == NULL)
383 return NULL;
384 }
385 memset(s, 0, sizeof(*s));
386 span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
387 span_log_set_protocol(&s->logging, "V.29 TX");
388 s->get_bit = get_bit;
389 s->get_bit_user_data = user_data;
390 s->carrier_phase_rate = dds_phase_ratef(CARRIER_NOMINAL_FREQ);
391 v29_tx_power(s, -14.0f);
392 v29_tx_restart(s, bit_rate, tep);
393 return s;
394 }
395 /*- End of function --------------------------------------------------------*/
396
397 SPAN_DECLARE(int) v29_tx_release(v29_tx_state_t *s)
398 {
399 return 0;
400 }
401 /*- End of function --------------------------------------------------------*/
402
403 SPAN_DECLARE(int) v29_tx_free(v29_tx_state_t *s)
404 {
405 free(s);
406 return 0;
407 }
408 /*- End of function --------------------------------------------------------*/
409 /*- End of file ------------------------------------------------------------*/

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.