comparison spandsp-0.0.6pre17/src/v17tx.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 * v17tx.c - ITU V.17 modem transmit part
5 *
6 * Written by Steve Underwood <steveu@coppice.org>
7 *
8 * Copyright (C) 2004 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: v17tx.c,v 1.75.4.1 2009/12/24 16:52:30 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/v17tx.h"
57
58 #include "spandsp/private/logging.h"
59 #include "spandsp/private/v17tx.h"
60
61 #if defined(SPANDSP_USE_FIXED_POINT)
62 #define SPANDSP_USE_FIXED_POINTx
63 #endif
64
65 #include "v17_v32bis_tx_constellation_maps.h"
66 #if defined(SPANDSP_USE_FIXED_POINT)
67 #include "v17_v32bis_tx_fixed_rrc.h"
68 #else
69 #include "v17_v32bis_tx_floating_rrc.h"
70 #endif
71
72 /*! The nominal frequency of the carrier, in Hertz */
73 #define CARRIER_NOMINAL_FREQ 1800.0f
74
75 /* Segments of the training sequence */
76 /*! The start of the optional TEP, that may preceed the actual training, in symbols */
77 #define V17_TRAINING_SEG_TEP_A 0
78 /*! The mid point of the optional TEP, that may preceed the actual training, in symbols */
79 #define V17_TRAINING_SEG_TEP_B (V17_TRAINING_SEG_TEP_A + 480)
80 /*! The start of training segment 1, in symbols */
81 #define V17_TRAINING_SEG_1 (V17_TRAINING_SEG_TEP_B + 48)
82 /*! The start of training segment 2, in symbols */
83 #define V17_TRAINING_SEG_2 (V17_TRAINING_SEG_1 + 256)
84 /*! The start of training segment 3, in symbols */
85 #define V17_TRAINING_SEG_3 (V17_TRAINING_SEG_2 + 2976)
86 /*! The start of training segment 4, in symbols */
87 #define V17_TRAINING_SEG_4 (V17_TRAINING_SEG_3 + 64)
88 /*! The start of training segment 4 in short training mode, in symbols */
89 #define V17_TRAINING_SHORT_SEG_4 (V17_TRAINING_SEG_2 + 38)
90 /*! The end of the training, in symbols */
91 #define V17_TRAINING_END (V17_TRAINING_SEG_4 + 48)
92 #define V17_TRAINING_SHUTDOWN_A (V17_TRAINING_END + 32)
93 /*! The end of the shutdown sequence, in symbols */
94 #define V17_TRAINING_SHUTDOWN_END (V17_TRAINING_SHUTDOWN_A + 48)
95
96 /*! The 16 bit pattern used in the bridge section of the training sequence */
97 #define V17_BRIDGE_WORD 0x8880
98
99 static __inline__ int scramble(v17_tx_state_t *s, int in_bit)
100 {
101 int out_bit;
102
103 //out_bit = (in_bit ^ (s->scramble_reg >> s->scrambler_tap) ^ (s->scramble_reg >> (23 - 1))) & 1;
104 out_bit = (in_bit ^ (s->scramble_reg >> (18 - 1)) ^ (s->scramble_reg >> (23 - 1))) & 1;
105 s->scramble_reg = (s->scramble_reg << 1) | out_bit;
106 return out_bit;
107 }
108 /*- End of function --------------------------------------------------------*/
109
110 #if defined(SPANDSP_USE_FIXED_POINT)
111 static __inline__ complexi16_t training_get(v17_tx_state_t *s)
112 #else
113 static __inline__ complexf_t training_get(v17_tx_state_t *s)
114 #endif
115 {
116 static const int cdba_to_abcd[4] =
117 {
118 2, 3, 1, 0
119 };
120 static const int dibit_to_step[4] =
121 {
122 1, 0, 2, 3
123 };
124 #if defined(SPANDSP_USE_FIXED_POINT)
125 static const complexi16_t zero = {0, 0};
126 #else
127 static const complexf_t zero = {0.0f, 0.0f};
128 #endif
129 int bits;
130 int shift;
131
132 if (++s->training_step <= V17_TRAINING_SEG_3)
133 {
134 if (s->training_step <= V17_TRAINING_SEG_2)
135 {
136 if (s->training_step <= V17_TRAINING_SEG_TEP_B)
137 {
138 /* Optional segment: Unmodulated carrier (talker echo protection) */
139 return v17_v32bis_abcd_constellation[0];
140 }
141 if (s->training_step <= V17_TRAINING_SEG_1)
142 {
143 /* Optional segment: silence (talker echo protection) */
144 return zero;
145 }
146 /* Segment 1: ABAB... */
147 return v17_v32bis_abcd_constellation[(s->training_step & 1) ^ 1];
148 }
149 /* Segment 2: CDBA... */
150 /* Apply the scrambler */
151 bits = scramble(s, 1);
152 bits = (bits << 1) | scramble(s, 1);
153 s->constellation_state = cdba_to_abcd[bits];
154 if (s->short_train && s->training_step == V17_TRAINING_SHORT_SEG_4)
155 {
156 /* Go straight to the ones test. */
157 s->training_step = V17_TRAINING_SEG_4;
158 }
159 return v17_v32bis_abcd_constellation[s->constellation_state];
160 }
161 /* Segment 3: Bridge... */
162 shift = ((s->training_step - V17_TRAINING_SEG_3 - 1) & 0x7) << 1;
163 //span_log(&s->logging, SPAN_LOG_FLOW, "Seg 3 shift %d\n", shift);
164 bits = scramble(s, V17_BRIDGE_WORD >> shift);
165 bits = (bits << 1) | scramble(s, V17_BRIDGE_WORD >> (shift + 1));
166 s->constellation_state = (s->constellation_state + dibit_to_step[bits]) & 3;
167 return v17_v32bis_abcd_constellation[s->constellation_state];
168 }
169 /*- End of function --------------------------------------------------------*/
170
171 static __inline__ int diff_and_convolutional_encode(v17_tx_state_t *s, int q)
172 {
173 static const uint8_t v32bis_4800_differential_encoder[4][4] =
174 {
175 {2, 3, 0, 1},
176 {0, 2, 1, 3},
177 {3, 1, 2, 0},
178 {1, 0, 3, 2}
179 };
180 static const uint8_t v17_differential_encoder[4][4] =
181 {
182 {0, 1, 2, 3},
183 {1, 2, 3, 0},
184 {2, 3, 0, 1},
185 {3, 0, 1, 2}
186 };
187 static const uint8_t v17_convolutional_coder[8][4] =
188 {
189 {0, 2, 3, 1},
190 {4, 7, 5, 6},
191 {1, 3, 2, 0},
192 {7, 4, 6, 5},
193 {2, 0, 1, 3},
194 {6, 5, 7, 4},
195 {3, 1, 0, 2},
196 {5, 6, 4, 7}
197 };
198
199 if (s->bits_per_symbol == 2)
200 {
201 /* 4800bps mode for V.32bis */
202 /* There is no trellis. We just differentially encode. */
203 s->diff = v32bis_4800_differential_encoder[s->diff][q & 0x03];
204 return s->diff;
205 }
206 /* Differentially encode */
207 s->diff = v17_differential_encoder[s->diff][q & 0x03];
208
209 /* Convolutionally encode the redundant bit */
210 s->convolution = v17_convolutional_coder[s->convolution][s->diff];
211
212 /* The final result is the combination of some uncoded bits, 2 differentially
213 encoded bits, and the convolutionally encoded redundant bit. */
214 return ((q << 1) & 0x78) | (s->diff << 1) | ((s->convolution >> 2) & 1);
215 }
216 /*- End of function --------------------------------------------------------*/
217
218 static int fake_get_bit(void *user_data)
219 {
220 return 1;
221 }
222 /*- End of function --------------------------------------------------------*/
223
224 #if defined(SPANDSP_USE_FIXED_POINT)
225 static __inline__ complexi16_t getbaud(v17_tx_state_t *s)
226 #else
227 static __inline__ complexf_t getbaud(v17_tx_state_t *s)
228 #endif
229 {
230 int i;
231 int bit;
232 int bits;
233
234 if (s->in_training)
235 {
236 if (s->training_step <= V17_TRAINING_END)
237 {
238 /* Send the training sequence */
239 if (s->training_step < V17_TRAINING_SEG_4)
240 return training_get(s);
241 /* The last step in training is to send some 1's */
242 if (++s->training_step > V17_TRAINING_END)
243 {
244 /* Training finished - commence normal operation. */
245 s->current_get_bit = s->get_bit;
246 s->in_training = FALSE;
247 }
248 }
249 else
250 {
251 if (++s->training_step > V17_TRAINING_SHUTDOWN_A)
252 {
253 /* The shutdown sequence is 32 bauds of all 1's, then 48 bauds
254 of silence */
255 #if defined(SPANDSP_USE_FIXED_POINT)
256 return complex_seti16(0, 0);
257 #else
258 return complex_setf(0.0f, 0.0f);
259 #endif
260 }
261 if (s->training_step == V17_TRAINING_SHUTDOWN_END)
262 {
263 if (s->status_handler)
264 s->status_handler(s->status_user_data, SIG_STATUS_SHUTDOWN_COMPLETE);
265 }
266 }
267 }
268 bits = 0;
269 for (i = 0; i < s->bits_per_symbol; i++)
270 {
271 if ((bit = s->current_get_bit(s->get_bit_user_data)) == SIG_STATUS_END_OF_DATA)
272 {
273 /* End of real data. Switch to the fake get_bit routine, until we
274 have shut down completely. */
275 if (s->status_handler)
276 s->status_handler(s->status_user_data, SIG_STATUS_END_OF_DATA);
277 s->current_get_bit = fake_get_bit;
278 s->in_training = TRUE;
279 bit = 1;
280 }
281 bits |= (scramble(s, bit) << i);
282 }
283 return s->constellation[diff_and_convolutional_encode(s, bits)];
284 }
285 /*- End of function --------------------------------------------------------*/
286
287 SPAN_DECLARE_NONSTD(int) v17_tx(v17_tx_state_t *s, int16_t amp[], int len)
288 {
289 #if defined(SPANDSP_USE_FIXED_POINT)
290 complexi_t x;
291 complexi_t z;
292 #else
293 complexf_t x;
294 complexf_t z;
295 #endif
296 int i;
297 int sample;
298
299 if (s->training_step >= V17_TRAINING_SHUTDOWN_END)
300 {
301 /* Once we have sent the shutdown sequence, we stop sending completely. */
302 return 0;
303 }
304 for (sample = 0; sample < len; sample++)
305 {
306 if ((s->baud_phase += 3) >= 10)
307 {
308 s->baud_phase -= 10;
309 s->rrc_filter[s->rrc_filter_step] =
310 s->rrc_filter[s->rrc_filter_step + V17_TX_FILTER_STEPS] = getbaud(s);
311 if (++s->rrc_filter_step >= V17_TX_FILTER_STEPS)
312 s->rrc_filter_step = 0;
313 }
314 /* Root raised cosine pulse shaping at baseband */
315 #if defined(SPANDSP_USE_FIXED_POINT)
316 x = complex_seti(0, 0);
317 for (i = 0; i < V17_TX_FILTER_STEPS; i++)
318 {
319 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;
320 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;
321 }
322 /* Now create and modulate the carrier */
323 x.re >>= 4;
324 x.im >>= 4;
325 z = dds_complexi(&(s->carrier_phase), s->carrier_phase_rate);
326 /* Don't bother saturating. We should never clip. */
327 i = (x.re*z.re - x.im*z.im) >> 15;
328 amp[sample] = (int16_t) ((i*s->gain) >> 15);
329 #else
330 x = complex_setf(0.0f, 0.0f);
331 for (i = 0; i < V17_TX_FILTER_STEPS; i++)
332 {
333 x.re += tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase][i]*s->rrc_filter[i + s->rrc_filter_step].re;
334 x.im += tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase][i]*s->rrc_filter[i + s->rrc_filter_step].im;
335 }
336 /* Now create and modulate the carrier */
337 z = dds_complexf(&(s->carrier_phase), s->carrier_phase_rate);
338 /* Don't bother saturating. We should never clip. */
339 amp[sample] = (int16_t) lfastrintf((x.re*z.re - x.im*z.im)*s->gain);
340 #endif
341 }
342 return sample;
343 }
344 /*- End of function --------------------------------------------------------*/
345
346 SPAN_DECLARE(void) v17_tx_power(v17_tx_state_t *s, float power)
347 {
348 /* The constellation design seems to keep the average power the same, regardless
349 of which bit rate is in use. */
350 #if defined(SPANDSP_USE_FIXED_POINT)
351 s->gain = 0.223f*powf(10.0f, (power - DBM0_MAX_POWER)/20.0f)*16.0f*(32767.0f/30672.52f)*32768.0f/TX_PULSESHAPER_GAIN;
352 #else
353 s->gain = 0.223f*powf(10.0f, (power - DBM0_MAX_POWER)/20.0f)*32768.0f/TX_PULSESHAPER_GAIN;
354 #endif
355 }
356 /*- End of function --------------------------------------------------------*/
357
358 SPAN_DECLARE(void) v17_tx_set_get_bit(v17_tx_state_t *s, get_bit_func_t get_bit, void *user_data)
359 {
360 if (s->get_bit == s->current_get_bit)
361 s->current_get_bit = get_bit;
362 s->get_bit = get_bit;
363 s->get_bit_user_data = user_data;
364 }
365 /*- End of function --------------------------------------------------------*/
366
367 SPAN_DECLARE(void) v17_tx_set_modem_status_handler(v17_tx_state_t *s, modem_tx_status_func_t handler, void *user_data)
368 {
369 s->status_handler = handler;
370 s->status_user_data = user_data;
371 }
372 /*- End of function --------------------------------------------------------*/
373
374 SPAN_DECLARE(logging_state_t *) v17_tx_get_logging_state(v17_tx_state_t *s)
375 {
376 return &s->logging;
377 }
378 /*- End of function --------------------------------------------------------*/
379
380 SPAN_DECLARE(int) v17_tx_restart(v17_tx_state_t *s, int bit_rate, int tep, int short_train)
381 {
382 switch (bit_rate)
383 {
384 case 14400:
385 s->bits_per_symbol = 6;
386 s->constellation = v17_v32bis_14400_constellation;
387 break;
388 case 12000:
389 s->bits_per_symbol = 5;
390 s->constellation = v17_v32bis_12000_constellation;
391 break;
392 case 9600:
393 s->bits_per_symbol = 4;
394 s->constellation = v17_v32bis_9600_constellation;
395 break;
396 case 7200:
397 s->bits_per_symbol = 3;
398 s->constellation = v17_v32bis_7200_constellation;
399 break;
400 case 4800:
401 /* This does not exist in the V.17 spec as a valid mode of operation.
402 However, it does exist in V.32bis, so it is here for completeness. */
403 s->bits_per_symbol = 2;
404 s->constellation = v17_v32bis_4800_constellation;
405 break;
406 default:
407 return -1;
408 }
409 s->bit_rate = bit_rate;
410 /* NB: some modems seem to use 3 instead of 1 for long training */
411 s->diff = (short_train) ? 0 : 1;
412 #if defined(SPANDSP_USE_FIXED_POINT)
413 memset(s->rrc_filter, 0, sizeof(s->rrc_filter));
414 #else
415 cvec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
416 #endif
417 s->rrc_filter_step = 0;
418 s->convolution = 0;
419 s->scramble_reg = 0x2ECDD5;
420 s->in_training = TRUE;
421 s->short_train = short_train;
422 s->training_step = (tep) ? V17_TRAINING_SEG_TEP_A : V17_TRAINING_SEG_1;
423 s->carrier_phase = 0;
424 s->baud_phase = 0;
425 s->constellation_state = 0;
426 s->current_get_bit = fake_get_bit;
427 return 0;
428 }
429 /*- End of function --------------------------------------------------------*/
430
431 SPAN_DECLARE(v17_tx_state_t *) v17_tx_init(v17_tx_state_t *s, int bit_rate, int tep, get_bit_func_t get_bit, void *user_data)
432 {
433 switch (bit_rate)
434 {
435 case 14400:
436 case 12000:
437 case 9600:
438 case 7200:
439 case 4800:
440 /* 4800 is an extension of V.17, to provide full converage of the V.32bis modes */
441 break;
442 default:
443 return NULL;
444 }
445 if (s == NULL)
446 {
447 if ((s = (v17_tx_state_t *) malloc(sizeof(*s))) == NULL)
448 return NULL;
449 }
450 memset(s, 0, sizeof(*s));
451 span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
452 span_log_set_protocol(&s->logging, "V.17 TX");
453 s->get_bit = get_bit;
454 s->get_bit_user_data = user_data;
455 //s->scrambler_tap = 18 - 1;
456 s->carrier_phase_rate = dds_phase_ratef(CARRIER_NOMINAL_FREQ);
457 v17_tx_power(s, -14.0f);
458 v17_tx_restart(s, bit_rate, tep, FALSE);
459 return s;
460 }
461 /*- End of function --------------------------------------------------------*/
462
463 SPAN_DECLARE(int) v17_tx_release(v17_tx_state_t *s)
464 {
465 return 0;
466 }
467 /*- End of function --------------------------------------------------------*/
468
469 SPAN_DECLARE(int) v17_tx_free(v17_tx_state_t *s)
470 {
471 free(s);
472 return 0;
473 }
474 /*- End of function --------------------------------------------------------*/
475 /*- End of file ------------------------------------------------------------*/

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