comparison spandsp-0.0.6pre17/src/v27ter_tx.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 * v27ter_tx.c - ITU V.27ter 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: v27ter_tx.c,v 1.76 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/v27ter_tx.h"
57
58 #include "spandsp/private/logging.h"
59 #include "spandsp/private/v27ter_tx.h"
60
61 #if defined(SPANDSP_USE_FIXED_POINT)
62 #include "v27ter_tx_4800_fixed_rrc.h"
63 #include "v27ter_tx_2400_fixed_rrc.h"
64 #else
65 #include "v27ter_tx_4800_floating_rrc.h"
66 #include "v27ter_tx_2400_floating_rrc.h"
67 #endif
68
69 /*! The nominal frequency of the carrier, in Hertz */
70 #define CARRIER_NOMINAL_FREQ 1800.0f
71
72 /* Segments of the training sequence */
73 /* V.27ter defines a long and a short sequence. FAX doesn't use the
74 short sequence, so it is not implemented here. */
75 /*! The start of training segment 1, in symbols */
76 #define V27TER_TRAINING_SEG_1 0
77 /*! The start of training segment 2, in symbols */
78 #define V27TER_TRAINING_SEG_2 (V27TER_TRAINING_SEG_1 + 320)
79 /*! The start of training segment 3, in symbols */
80 #define V27TER_TRAINING_SEG_3 (V27TER_TRAINING_SEG_2 + 32)
81 /*! The start of training segment 4, in symbols */
82 #define V27TER_TRAINING_SEG_4 (V27TER_TRAINING_SEG_3 + 50)
83 /*! The start of training segment 5, in symbols */
84 #define V27TER_TRAINING_SEG_5 (V27TER_TRAINING_SEG_4 + 1074)
85 /*! The end of the training, in symbols */
86 #define V27TER_TRAINING_END (V27TER_TRAINING_SEG_5 + 8)
87 /*! The end of the shutdown sequence, in symbols */
88 #define V27TER_TRAINING_SHUTDOWN_END (V27TER_TRAINING_END + 32)
89
90 static int fake_get_bit(void *user_data)
91 {
92 return 1;
93 }
94 /*- End of function --------------------------------------------------------*/
95
96 static __inline__ int scramble(v27ter_tx_state_t *s, int in_bit)
97 {
98 int out_bit;
99
100 /* This scrambler is really quite messy to implement. There seems to be no efficient shortcut */
101 out_bit = (in_bit ^ (s->scramble_reg >> 5) ^ (s->scramble_reg >> 6)) & 1;
102 if (s->scrambler_pattern_count >= 33)
103 {
104 out_bit ^= 1;
105 s->scrambler_pattern_count = 0;
106 }
107 else
108 {
109 if ((((s->scramble_reg >> 7) ^ out_bit) & ((s->scramble_reg >> 8) ^ out_bit) & ((s->scramble_reg >> 11) ^ out_bit) & 1))
110 s->scrambler_pattern_count = 0;
111 else
112 s->scrambler_pattern_count++;
113 }
114 s->scramble_reg = (s->scramble_reg << 1) | out_bit;
115 return out_bit;
116 }
117 /*- End of function --------------------------------------------------------*/
118
119 static __inline__ int get_scrambled_bit(v27ter_tx_state_t *s)
120 {
121 int bit;
122
123 if ((bit = s->current_get_bit(s->get_bit_user_data)) == SIG_STATUS_END_OF_DATA)
124 {
125 /* End of real data. Switch to the fake get_bit routine, until we
126 have shut down completely. */
127 if (s->status_handler)
128 s->status_handler(s->status_user_data, SIG_STATUS_END_OF_DATA);
129 s->current_get_bit = fake_get_bit;
130 s->in_training = TRUE;
131 bit = 1;
132 }
133 return scramble(s, bit);
134 }
135 /*- End of function --------------------------------------------------------*/
136
137 #if defined(SPANDSP_USE_FIXED_POINT)
138 static complexi16_t getbaud(v27ter_tx_state_t *s)
139 #else
140 static complexf_t getbaud(v27ter_tx_state_t *s)
141 #endif
142 {
143 static const int phase_steps_4800[8] =
144 {
145 1, 0, 2, 3, 6, 7, 5, 4
146 };
147 static const int phase_steps_2400[4] =
148 {
149 0, 2, 6, 4
150 };
151 #if defined(SPANDSP_USE_FIXED_POINT)
152 static const complexi16_t constellation[8] =
153 {
154 { 1414, 0000}, /* 0deg */
155 { 1000, 1000}, /* 45deg */
156 { 0000, 1414}, /* 90deg */
157 {-1000, 1000}, /* 135deg */
158 {-1414, 0000}, /* 180deg */
159 {-1000, -1000}, /* 225deg */
160 { 0000, -1414}, /* 270deg */
161 { 1000, -1000} /* 315deg */
162 };
163 static const complexi16_t zero = {0, 0};
164 #else
165 static const complexf_t constellation[8] =
166 {
167 { 1.414f, 0.0f}, /* 0deg */
168 { 1.0f, 1.0f}, /* 45deg */
169 { 0.0f, 1.414f}, /* 90deg */
170 {-1.0f, 1.0f}, /* 135deg */
171 {-1.414f, 0.0f}, /* 180deg */
172 {-1.0f, -1.0f}, /* 225deg */
173 { 0.0f, -1.414f}, /* 270deg */
174 { 1.0f, -1.0f} /* 315deg */
175 };
176 static const complexf_t zero = {0.0f, 0.0f};
177 #endif
178 int bits;
179
180 if (s->in_training)
181 {
182 /* Send the training sequence */
183 if (++s->training_step <= V27TER_TRAINING_SEG_5)
184 {
185 if (s->training_step <= V27TER_TRAINING_SEG_4)
186 {
187 if (s->training_step <= V27TER_TRAINING_SEG_2)
188 {
189 /* Segment 1: Unmodulated carrier (talker echo protection) */
190 return constellation[0];
191 }
192 if (s->training_step <= V27TER_TRAINING_SEG_3)
193 {
194 /* Segment 2: Silence */
195 return zero;
196 }
197 /* Segment 3: Regular reversals... */
198 s->constellation_state = (s->constellation_state + 4) & 7;
199 return constellation[s->constellation_state];
200 }
201 /* Segment 4: Scrambled reversals... */
202 /* Apply the 1 + x^-6 + x^-7 scrambler. We want every third
203 bit from the scrambler. */
204 bits = get_scrambled_bit(s) << 2;
205 get_scrambled_bit(s);
206 get_scrambled_bit(s);
207 s->constellation_state = (s->constellation_state + bits) & 7;
208 return constellation[s->constellation_state];
209 }
210 /* We should be in the block of test ones, or shutdown ones, if we get here. */
211 /* There is no graceful shutdown procedure defined for V.27ter. Just
212 send some ones, to ensure we get the real data bits through, even
213 with bad ISI. */
214 if (s->training_step == V27TER_TRAINING_END + 1)
215 {
216 /* End of the last segment - segment 5: All ones */
217 /* Switch from the fake get_bit routine, to the user supplied real
218 one, and we are up and running. */
219 s->current_get_bit = s->get_bit;
220 s->in_training = FALSE;
221 }
222 if (s->training_step == V27TER_TRAINING_SHUTDOWN_END)
223 {
224 if (s->status_handler)
225 s->status_handler(s->status_user_data, SIG_STATUS_SHUTDOWN_COMPLETE);
226 }
227 }
228 /* 4800bps uses 8 phases. 2400bps uses 4 phases. */
229 if (s->bit_rate == 4800)
230 {
231 bits = get_scrambled_bit(s);
232 bits = (bits << 1) | get_scrambled_bit(s);
233 bits = (bits << 1) | get_scrambled_bit(s);
234 bits = phase_steps_4800[bits];
235 }
236 else
237 {
238 bits = get_scrambled_bit(s);
239 bits = (bits << 1) | get_scrambled_bit(s);
240 bits = phase_steps_2400[bits];
241 }
242 s->constellation_state = (s->constellation_state + bits) & 7;
243 return constellation[s->constellation_state];
244 }
245 /*- End of function --------------------------------------------------------*/
246
247 SPAN_DECLARE_NONSTD(int) v27ter_tx(v27ter_tx_state_t *s, int16_t amp[], int len)
248 {
249 #if defined(SPANDSP_USE_FIXED_POINT)
250 complexi_t x;
251 complexi_t z;
252 #else
253 complexf_t x;
254 complexf_t z;
255 #endif
256 int i;
257 int sample;
258
259 if (s->training_step >= V27TER_TRAINING_SHUTDOWN_END)
260 {
261 /* Once we have sent the shutdown symbols, we stop sending completely. */
262 return 0;
263 }
264 /* The symbol rates for the two bit rates are different. This makes it difficult to
265 merge both generation procedures into a single efficient loop. We do not bother
266 trying. We use two independent loops, filter coefficients, etc. */
267 if (s->bit_rate == 4800)
268 {
269 for (sample = 0; sample < len; sample++)
270 {
271 if (++s->baud_phase >= 5)
272 {
273 s->baud_phase -= 5;
274 s->rrc_filter[s->rrc_filter_step] =
275 s->rrc_filter[s->rrc_filter_step + V27TER_TX_FILTER_STEPS] = getbaud(s);
276 if (++s->rrc_filter_step >= V27TER_TX_FILTER_STEPS)
277 s->rrc_filter_step = 0;
278 }
279 /* Root raised cosine pulse shaping at baseband */
280 #if defined(SPANDSP_USE_FIXED_POINT)
281 x = complex_seti(0, 0);
282 for (i = 0; i < V27TER_TX_FILTER_STEPS; i++)
283 {
284 x.re += (int32_t) tx_pulseshaper_4800[TX_PULSESHAPER_4800_COEFF_SETS - 1 - s->baud_phase][i]*(int32_t) s->rrc_filter[i + s->rrc_filter_step].re;
285 x.im += (int32_t) tx_pulseshaper_4800[TX_PULSESHAPER_4800_COEFF_SETS - 1 - s->baud_phase][i]*(int32_t) s->rrc_filter[i + s->rrc_filter_step].im;
286 }
287 /* Now create and modulate the carrier */
288 x.re >>= 14;
289 x.im >>= 14;
290 z = dds_complexi(&(s->carrier_phase), s->carrier_phase_rate);
291 /* Don't bother saturating. We should never clip. */
292 i = (x.re*z.re - x.im*z.im) >> 15;
293 amp[sample] = (int16_t) ((i*s->gain_4800) >> 15);
294 #else
295 x = complex_setf(0.0f, 0.0f);
296 for (i = 0; i < V27TER_TX_FILTER_STEPS; i++)
297 {
298 x.re += tx_pulseshaper_4800[TX_PULSESHAPER_4800_COEFF_SETS - 1 - s->baud_phase][i]*s->rrc_filter[i + s->rrc_filter_step].re;
299 x.im += tx_pulseshaper_4800[TX_PULSESHAPER_4800_COEFF_SETS - 1 - s->baud_phase][i]*s->rrc_filter[i + s->rrc_filter_step].im;
300 }
301 /* Now create and modulate the carrier */
302 z = dds_complexf(&(s->carrier_phase), s->carrier_phase_rate);
303 /* Don't bother saturating. We should never clip. */
304 amp[sample] = (int16_t) lfastrintf((x.re*z.re - x.im*z.im)*s->gain_4800);
305 #endif
306 }
307 }
308 else
309 {
310 for (sample = 0; sample < len; sample++)
311 {
312 if ((s->baud_phase += 3) >= 20)
313 {
314 s->baud_phase -= 20;
315 s->rrc_filter[s->rrc_filter_step] =
316 s->rrc_filter[s->rrc_filter_step + V27TER_TX_FILTER_STEPS] = getbaud(s);
317 if (++s->rrc_filter_step >= V27TER_TX_FILTER_STEPS)
318 s->rrc_filter_step = 0;
319 }
320 /* Root raised cosine pulse shaping at baseband */
321 #if defined(SPANDSP_USE_FIXED_POINT)
322 x = complex_seti(0, 0);
323 for (i = 0; i < V27TER_TX_FILTER_STEPS; i++)
324 {
325 x.re += (int32_t) tx_pulseshaper_2400[TX_PULSESHAPER_2400_COEFF_SETS - 1 - s->baud_phase][i]*(int32_t) s->rrc_filter[i + s->rrc_filter_step].re;
326 x.im += (int32_t) tx_pulseshaper_2400[TX_PULSESHAPER_2400_COEFF_SETS - 1 - s->baud_phase][i]*(int32_t) s->rrc_filter[i + s->rrc_filter_step].im;
327 }
328 /* Now create and modulate the carrier */
329 x.re >>= 14;
330 x.im >>= 14;
331 z = dds_complexi(&(s->carrier_phase), s->carrier_phase_rate);
332 /* Don't bother saturating. We should never clip. */
333 i = (x.re*z.re - x.im*z.im) >> 15;
334 amp[sample] = (int16_t) ((i*s->gain_2400) >> 15);
335 #else
336 x = complex_setf(0.0f, 0.0f);
337 for (i = 0; i < V27TER_TX_FILTER_STEPS; i++)
338 {
339 x.re += tx_pulseshaper_2400[TX_PULSESHAPER_2400_COEFF_SETS - 1 - s->baud_phase][i]*s->rrc_filter[i + s->rrc_filter_step].re;
340 x.im += tx_pulseshaper_2400[TX_PULSESHAPER_2400_COEFF_SETS - 1 - s->baud_phase][i]*s->rrc_filter[i + s->rrc_filter_step].im;
341 }
342 /* Now create and modulate the carrier */
343 z = dds_complexf(&(s->carrier_phase), s->carrier_phase_rate);
344 /* Don't bother saturating. We should never clip. */
345 amp[sample] = (int16_t) lfastrintf((x.re*z.re - x.im*z.im)*s->gain_2400);
346 #endif
347 }
348 }
349 return sample;
350 }
351 /*- End of function --------------------------------------------------------*/
352
353 SPAN_DECLARE(void) v27ter_tx_power(v27ter_tx_state_t *s, float power)
354 {
355 float l;
356
357 l = powf(10.0f, (power - DBM0_MAX_POWER)/20.0f)*32768.0f;
358 #if defined(SPANDSP_USE_FIXED_POINT)
359 s->gain_2400 = 16.0f*1.024f*(32767.0f/28828.51f)*l/TX_PULSESHAPER_2400_GAIN;
360 s->gain_4800 = 16.0f*1.024f*(32767.0f/28828.46f)*l/TX_PULSESHAPER_4800_GAIN;
361 #else
362 s->gain_2400 = l/TX_PULSESHAPER_2400_GAIN;
363 s->gain_4800 = l/TX_PULSESHAPER_4800_GAIN;
364 #endif
365 }
366 /*- End of function --------------------------------------------------------*/
367
368 SPAN_DECLARE(void) v27ter_tx_set_get_bit(v27ter_tx_state_t *s, get_bit_func_t get_bit, void *user_data)
369 {
370 if (s->get_bit == s->current_get_bit)
371 s->current_get_bit = get_bit;
372 s->get_bit = get_bit;
373 s->get_bit_user_data = user_data;
374 }
375 /*- End of function --------------------------------------------------------*/
376
377 SPAN_DECLARE(void) v27ter_tx_set_modem_status_handler(v27ter_tx_state_t *s, modem_tx_status_func_t handler, void *user_data)
378 {
379 s->status_handler = handler;
380 s->status_user_data = user_data;
381 }
382 /*- End of function --------------------------------------------------------*/
383
384 SPAN_DECLARE(logging_state_t *) v27ter_tx_get_logging_state(v27ter_tx_state_t *s)
385 {
386 return &s->logging;
387 }
388 /*- End of function --------------------------------------------------------*/
389
390 SPAN_DECLARE(int) v27ter_tx_restart(v27ter_tx_state_t *s, int bit_rate, int tep)
391 {
392 if (bit_rate != 4800 && bit_rate != 2400)
393 return -1;
394 s->bit_rate = bit_rate;
395 #if defined(SPANDSP_USE_FIXED_POINT)
396 memset(s->rrc_filter, 0, sizeof(s->rrc_filter));
397 #else
398 cvec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
399 #endif
400 s->rrc_filter_step = 0;
401 s->scramble_reg = 0x3C;
402 s->scrambler_pattern_count = 0;
403 s->in_training = TRUE;
404 s->training_step = (tep) ? V27TER_TRAINING_SEG_1 : V27TER_TRAINING_SEG_2;
405 s->carrier_phase = 0;
406 s->baud_phase = 0;
407 s->constellation_state = 0;
408 s->current_get_bit = fake_get_bit;
409 return 0;
410 }
411 /*- End of function --------------------------------------------------------*/
412
413 SPAN_DECLARE(v27ter_tx_state_t *) v27ter_tx_init(v27ter_tx_state_t *s, int bit_rate, int tep, get_bit_func_t get_bit, void *user_data)
414 {
415 switch (bit_rate)
416 {
417 case 4800:
418 case 2400:
419 break;
420 default:
421 return NULL;
422 }
423 if (s == NULL)
424 {
425 if ((s = (v27ter_tx_state_t *) malloc(sizeof(*s))) == NULL)
426 return NULL;
427 }
428 memset(s, 0, sizeof(*s));
429 span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
430 span_log_set_protocol(&s->logging, "V.27ter TX");
431 s->get_bit = get_bit;
432 s->get_bit_user_data = user_data;
433 s->carrier_phase_rate = dds_phase_ratef(CARRIER_NOMINAL_FREQ);
434 v27ter_tx_power(s, -14.0f);
435 v27ter_tx_restart(s, bit_rate, tep);
436 return s;
437 }
438 /*- End of function --------------------------------------------------------*/
439
440 SPAN_DECLARE(int) v27ter_tx_release(v27ter_tx_state_t *s)
441 {
442 return 0;
443 }
444 /*- End of function --------------------------------------------------------*/
445
446 SPAN_DECLARE(int) v27ter_tx_free(v27ter_tx_state_t *s)
447 {
448 free(s);
449 return 0;
450 }
451 /*- End of function --------------------------------------------------------*/
452 /*- End of file ------------------------------------------------------------*/

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