Mercurial > hg > audiostuff
comparison spandsp-0.0.3/spandsp-0.0.3/src/v27ter_tx.c @ 5:f762bf195c4b
import spandsp-0.0.3
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 16:00:21 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
4:26cd8f1ef0b1 | 5:f762bf195c4b |
---|---|
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 General Public License version 2, as | |
14 * 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 General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU General Public License | |
22 * 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.48 2006/11/28 16:59:57 steveu Exp $ | |
26 */ | |
27 | |
28 /*! \file */ | |
29 | |
30 #ifdef 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 | |
45 #include "spandsp/telephony.h" | |
46 #include "spandsp/logging.h" | |
47 #include "spandsp/complex.h" | |
48 #include "spandsp/vector_float.h" | |
49 #include "spandsp/complex_vector_float.h" | |
50 #include "spandsp/async.h" | |
51 #include "spandsp/dds.h" | |
52 #include "spandsp/power_meter.h" | |
53 | |
54 #include "spandsp/v27ter_tx.h" | |
55 | |
56 #define CARRIER_NOMINAL_FREQ 1800.0f | |
57 | |
58 /* Segments of the training sequence */ | |
59 /* V.27ter defines a long and a short sequence. FAX doesn't use the | |
60 short sequence, so it is not implemented here. */ | |
61 #define V27TER_TRAINING_SEG_1 0 | |
62 #define V27TER_TRAINING_SEG_2 (V27TER_TRAINING_SEG_1 + 320) | |
63 #define V27TER_TRAINING_SEG_3 (V27TER_TRAINING_SEG_2 + 32) | |
64 #define V27TER_TRAINING_SEG_4 (V27TER_TRAINING_SEG_3 + 50) | |
65 #define V27TER_TRAINING_SEG_5 (V27TER_TRAINING_SEG_4 + 1074) | |
66 #define V27TER_TRAINING_END (V27TER_TRAINING_SEG_5 + 8) | |
67 #define V27TER_TRAINING_SHUTDOWN_END (V27TER_TRAINING_END + 32) | |
68 | |
69 /* Raised root cosine pulse shaping; Beta = 0.5; 4 symbols either | |
70 side of the centre. */ | |
71 /* Created with mkshape -r 0.025 0.5 181 -l and then split up */ | |
72 #define PULSESHAPER_2400_GAIN (19.972065748f/20.0f) | |
73 #define PULSESHAPER_2400_COEFF_SETS 20 | |
74 static const float pulseshaper_2400[PULSESHAPER_2400_COEFF_SETS][V27TER_TX_FILTER_STEPS] = | |
75 { | |
76 { | |
77 0.0050051219f, /* Filter 0 */ | |
78 0.0107180844f, | |
79 -0.0150077814f, | |
80 -0.0750272071f, | |
81 0.5786341413f, | |
82 0.5786341413f, | |
83 -0.0750272071f, | |
84 -0.0150077814f, | |
85 0.0107180844f | |
86 }, | |
87 { | |
88 0.0036624469f, /* Filter 1 */ | |
89 0.0131516633f, | |
90 -0.0107913392f, | |
91 -0.0957820135f, | |
92 0.6671466059f, | |
93 0.4891745311f, | |
94 -0.0541239470f, | |
95 -0.0179109014f, | |
96 0.0079099936f | |
97 }, | |
98 { | |
99 0.0020204744f, /* Filter 2 */ | |
100 0.0150588729f, | |
101 -0.0053908083f, | |
102 -0.1154114754f, | |
103 0.7528295479f, | |
104 0.4006032722f, | |
105 -0.0339459430f, | |
106 -0.0194500407f, | |
107 0.0048904515f | |
108 }, | |
109 { | |
110 0.0001596234f, /* Filter 3 */ | |
111 0.0163079778f, | |
112 0.0009858079f, | |
113 -0.1328632049f, | |
114 0.8338068363f, | |
115 0.3146585634f, | |
116 -0.0152415667f, | |
117 -0.0196492903f, | |
118 0.0018247182f | |
119 }, | |
120 { | |
121 -0.0018233575f, /* Filter 4 */ | |
122 0.0167957238f, | |
123 0.0080554403f, | |
124 -0.1470417557f, | |
125 0.9082626683f, | |
126 0.2329352195f, | |
127 0.0013822552f, | |
128 -0.0186004475f, | |
129 -0.0011283792f | |
130 }, | |
131 { | |
132 -0.0038199491f, /* Filter 5 */ | |
133 0.0164546659f, | |
134 0.0154676597f, | |
135 -0.1568448230f, | |
136 0.9744947974f, | |
137 0.1568443643f, | |
138 0.0154698286f, | |
139 -0.0164532877f, | |
140 -0.0038242967f | |
141 }, | |
142 { | |
143 -0.0057152767f, /* Filter 6 */ | |
144 0.0152590213f, | |
145 0.0228163087f, | |
146 -0.1612020164f, | |
147 1.0309651039f, | |
148 0.0875801110f, | |
149 0.0267201501f, | |
150 -0.0134037738f, | |
151 -0.0061394831f | |
152 }, | |
153 { | |
154 -0.0073941287f, /* Filter 7 */ | |
155 0.0132286539f, | |
156 0.0296547979f, | |
157 -0.1591148676f, | |
158 1.0763457753f, | |
159 0.0260941722f, | |
160 0.0349842710f, | |
161 -0.0096808822f, | |
162 -0.0079766730f | |
163 }, | |
164 { | |
165 -0.0087472825f, /* Filter 8 */ | |
166 0.0104308721f, | |
167 0.0355146231f, | |
168 -0.1496966290f, | |
169 1.1095595051f, | |
170 -0.0269209682f, | |
171 0.0402570324f, | |
172 -0.0055327477f, | |
173 -0.0092685626f | |
174 }, | |
175 { | |
176 -0.0096778115f, /* Filter 9 */ | |
177 0.0069798134f, | |
178 0.0399264862f, | |
179 -0.1322103702f, | |
180 1.1298123136f, | |
181 -0.0710400038f, | |
182 0.0426638320f, | |
183 -0.0012128224f, | |
184 -0.0099797659f | |
185 }, | |
186 { | |
187 -0.0101070340f, /* Filter 10 */ | |
188 0.0030333009f, | |
189 0.0424432507f, | |
190 -0.1061038872f, | |
191 1.1366178484f, | |
192 -0.1061038872f, | |
193 0.0424432507f, | |
194 0.0030333009f, | |
195 -0.0101070340f | |
196 }, | |
197 { | |
198 -0.0099797659f, /* Filter 11 */ | |
199 -0.0012128224f, | |
200 0.0426638320f, | |
201 -0.0710400038f, | |
202 1.1298123136f, | |
203 -0.1322103702f, | |
204 0.0399264862f, | |
205 0.0069798134f, | |
206 -0.0096778115f | |
207 }, | |
208 { | |
209 -0.0092685626f, /* Filter 12 */ | |
210 -0.0055327477f, | |
211 0.0402570324f, | |
212 -0.0269209682f, | |
213 1.1095595051f, | |
214 -0.1496966290f, | |
215 0.0355146231f, | |
216 0.0104308721f, | |
217 -0.0087472825f | |
218 }, | |
219 { | |
220 -0.0079766730f, /* Filter 13 */ | |
221 -0.0096808822f, | |
222 0.0349842710f, | |
223 0.0260941722f, | |
224 1.0763457753f, | |
225 -0.1591148676f, | |
226 0.0296547979f, | |
227 0.0132286539f, | |
228 -0.0073941287f | |
229 }, | |
230 { | |
231 -0.0061394831f, /* Filter 14 */ | |
232 -0.0134037738f, | |
233 0.0267201501f, | |
234 0.0875801110f, | |
235 1.0309651039f, | |
236 -0.1612020164f, | |
237 0.0228163087f, | |
238 0.0152590213f, | |
239 -0.0057152767f | |
240 }, | |
241 { | |
242 -0.0038242967f, /* Filter 15 */ | |
243 -0.0164532877f, | |
244 0.0154698286f, | |
245 0.1568443643f, | |
246 0.9744947974f, | |
247 -0.1568448230f, | |
248 0.0154676597f, | |
249 0.0164546659f, | |
250 -0.0038199491f | |
251 }, | |
252 { | |
253 -0.0011283792f, /* Filter 16 */ | |
254 -0.0186004475f, | |
255 0.0013822552f, | |
256 0.2329352195f, | |
257 0.9082626683f, | |
258 -0.1470417557f, | |
259 0.0080554403f, | |
260 0.0167957238f, | |
261 -0.0018233575f | |
262 }, | |
263 { | |
264 0.0018247182f, /* Filter 17 */ | |
265 -0.0196492903f, | |
266 -0.0152415667f, | |
267 0.3146585634f, | |
268 0.8338068363f, | |
269 -0.1328632049f, | |
270 0.0009858079f, | |
271 0.0163079778f, | |
272 0.0001596234f | |
273 }, | |
274 { | |
275 0.0048904515f, /* Filter 18 */ | |
276 -0.0194500407f, | |
277 -0.0339459430f, | |
278 0.4006032722f, | |
279 0.7528295479f, | |
280 -0.1154114754f, | |
281 -0.0053908083f, | |
282 0.0150588729f, | |
283 0.0020204744f | |
284 }, | |
285 { | |
286 0.0079099936f, /* Filter 19 */ | |
287 -0.0179109014f, | |
288 -0.0541239470f, | |
289 0.4891745311f, | |
290 0.6671466059f, | |
291 -0.0957820135f, | |
292 -0.0107913392f, | |
293 0.0131516633f, | |
294 0.0036624469f | |
295 }, | |
296 }; | |
297 | |
298 /* Raised root cosine pulse shaping; Beta = 0.5; 4 symbols either | |
299 side of the centre. */ | |
300 /* Created with mkshape -r 0.1 0.5 45 -l and then split up */ | |
301 #define PULSESHAPER_4800_GAIN (4.9913162900f/5.0f) | |
302 #define PULSESHAPER_4800_COEFF_SETS 5 | |
303 static const float pulseshaper_4800[PULSESHAPER_4800_COEFF_SETS][V27TER_TX_FILTER_STEPS] = | |
304 { | |
305 { | |
306 0.0020173211f, /* Filter 0 */ | |
307 0.0150576434f, | |
308 -0.0053888047f, | |
309 -0.1154099010f, | |
310 0.7528286821f, | |
311 0.4006013374f, | |
312 -0.0339462085f, | |
313 -0.0194477281f, | |
314 0.0048918464f | |
315 }, | |
316 { | |
317 -0.0057162575f, /* Filter 1 */ | |
318 0.0152563286f, | |
319 0.0228163350f, | |
320 -0.1612000503f, | |
321 1.0309660372f, | |
322 0.0875788553f, | |
323 0.0267182476f, | |
324 -0.0134032156f, | |
325 -0.0061365979f | |
326 }, | |
327 { | |
328 -0.0101052019f, /* Filter 2 */ | |
329 0.0030314952f, | |
330 0.0424414442f, | |
331 -0.1061032862f, | |
332 1.1366196464f, | |
333 -0.1061032862f, | |
334 0.0424414442f, | |
335 0.0030314952f, | |
336 -0.0101052019f | |
337 }, | |
338 { | |
339 -0.0061365979f, /* Filter 3 */ | |
340 -0.0134032156f, | |
341 0.0267182476f, | |
342 0.0875788553f, | |
343 1.0309660372f, | |
344 -0.1612000503f, | |
345 0.0228163350f, | |
346 0.0152563286f, | |
347 -0.0057162575f | |
348 }, | |
349 { | |
350 0.0048918464f, /* Filter 4 */ | |
351 -0.0194477281f, | |
352 -0.0339462085f, | |
353 0.4006013374f, | |
354 0.7528286821f, | |
355 -0.1154099010f, | |
356 -0.0053888047f, | |
357 0.0150576434f, | |
358 0.0020173211f | |
359 }, | |
360 }; | |
361 | |
362 static int fake_get_bit(void *user_data) | |
363 { | |
364 return 1; | |
365 } | |
366 /*- End of function --------------------------------------------------------*/ | |
367 | |
368 static __inline__ int scramble(v27ter_tx_state_t *s, int in_bit) | |
369 { | |
370 int out_bit; | |
371 | |
372 /* This scrambler is really quite messy to implement. There seems to be no efficient shortcut */ | |
373 out_bit = (in_bit ^ (s->scramble_reg >> 5) ^ (s->scramble_reg >> 6)) & 1; | |
374 if (s->scrambler_pattern_count >= 33) | |
375 { | |
376 out_bit ^= 1; | |
377 s->scrambler_pattern_count = 0; | |
378 } | |
379 else | |
380 { | |
381 if ((((s->scramble_reg >> 7) ^ out_bit) & ((s->scramble_reg >> 8) ^ out_bit) & ((s->scramble_reg >> 11) ^ out_bit) & 1)) | |
382 s->scrambler_pattern_count = 0; | |
383 else | |
384 s->scrambler_pattern_count++; | |
385 } | |
386 s->scramble_reg = (s->scramble_reg << 1) | out_bit; | |
387 return out_bit; | |
388 } | |
389 /*- End of function --------------------------------------------------------*/ | |
390 | |
391 static __inline__ int get_scrambled_bit(v27ter_tx_state_t *s) | |
392 { | |
393 int bit; | |
394 | |
395 if ((bit = s->current_get_bit(s->user_data)) == PUTBIT_END_OF_DATA) | |
396 { | |
397 /* End of real data. Switch to the fake get_bit routine, until we | |
398 have shut down completely. */ | |
399 s->current_get_bit = fake_get_bit; | |
400 s->in_training = TRUE; | |
401 bit = 1; | |
402 } | |
403 return scramble(s, bit); | |
404 } | |
405 /*- End of function --------------------------------------------------------*/ | |
406 | |
407 static complexf_t getbaud(v27ter_tx_state_t *s) | |
408 { | |
409 static const int phase_steps_4800[8] = | |
410 { | |
411 1, 0, 2, 3, 6, 7, 5, 4 | |
412 }; | |
413 static const int phase_steps_2400[4] = | |
414 { | |
415 0, 2, 6, 4 | |
416 }; | |
417 static const complexf_t constellation[8] = | |
418 { | |
419 { 1.414f, 0.0f}, /* 0deg */ | |
420 { 1.0f, 1.0f}, /* 45deg */ | |
421 { 0.0f, 1.414f}, /* 90deg */ | |
422 {-1.0f, 1.0f}, /* 135deg */ | |
423 {-1.414f, 0.0f}, /* 180deg */ | |
424 {-1.0f, -1.0f}, /* 225deg */ | |
425 { 0.0f, -1.414f}, /* 270deg */ | |
426 { 1.0f, -1.0f} /* 315deg */ | |
427 }; | |
428 int bits; | |
429 | |
430 if (s->in_training) | |
431 { | |
432 /* Send the training sequence */ | |
433 if (++s->training_step <= V27TER_TRAINING_SEG_5) | |
434 { | |
435 if (s->training_step <= V27TER_TRAINING_SEG_4) | |
436 { | |
437 if (s->training_step <= V27TER_TRAINING_SEG_2) | |
438 { | |
439 /* Segment 1: Unmodulated carrier (talker echo protection) */ | |
440 return constellation[0]; | |
441 } | |
442 if (s->training_step <= V27TER_TRAINING_SEG_3) | |
443 { | |
444 /* Segment 2: Silence */ | |
445 return complex_setf(0.0, 0.0); | |
446 } | |
447 /* Segment 3: Regular reversals... */ | |
448 s->constellation_state = (s->constellation_state + 4) & 7; | |
449 return constellation[s->constellation_state]; | |
450 } | |
451 /* Segment 4: Scrambled reversals... */ | |
452 /* Apply the 1 + x^-6 + x^-7 scrambler. We want every third | |
453 bit from the scrambler. */ | |
454 bits = get_scrambled_bit(s) << 2; | |
455 get_scrambled_bit(s); | |
456 get_scrambled_bit(s); | |
457 s->constellation_state = (s->constellation_state + bits) & 7; | |
458 return constellation[s->constellation_state]; | |
459 } | |
460 /* We should be in the block of test ones, or shutdown ones, if we get here. */ | |
461 /* There is no graceful shutdown procedure defined for V.27ter. Just | |
462 send some ones, to ensure we get the real data bits through, even | |
463 with bad ISI. */ | |
464 if (s->training_step == V27TER_TRAINING_END + 1) | |
465 { | |
466 /* End of the last segment - segment 5: All ones */ | |
467 /* Switch from the fake get_bit routine, to the user supplied real | |
468 one, and we are up and running. */ | |
469 s->current_get_bit = s->get_bit; | |
470 s->in_training = FALSE; | |
471 } | |
472 } | |
473 /* 4800bps uses 8 phases. 2400bps uses 4 phases. */ | |
474 if (s->bit_rate == 4800) | |
475 { | |
476 bits = get_scrambled_bit(s); | |
477 bits = (bits << 1) | get_scrambled_bit(s); | |
478 bits = (bits << 1) | get_scrambled_bit(s); | |
479 bits = phase_steps_4800[bits]; | |
480 } | |
481 else | |
482 { | |
483 bits = get_scrambled_bit(s); | |
484 bits = (bits << 1) | get_scrambled_bit(s); | |
485 bits = phase_steps_2400[bits]; | |
486 } | |
487 s->constellation_state = (s->constellation_state + bits) & 7; | |
488 return constellation[s->constellation_state]; | |
489 } | |
490 /*- End of function --------------------------------------------------------*/ | |
491 | |
492 int v27ter_tx(v27ter_tx_state_t *s, int16_t amp[], int len) | |
493 { | |
494 complexf_t x; | |
495 complexf_t z; | |
496 int i; | |
497 int sample; | |
498 | |
499 if (s->training_step >= V27TER_TRAINING_SHUTDOWN_END) | |
500 { | |
501 /* Once we have sent the shutdown symbols, we stop sending completely. */ | |
502 return 0; | |
503 } | |
504 /* The symbol rates for the two bit rates are different. This makes it difficult to | |
505 merge both generation procedures into a single efficient loop. We do not bother | |
506 trying. We use two independent loops, filter coefficients, etc. */ | |
507 if (s->bit_rate == 4800) | |
508 { | |
509 for (sample = 0; sample < len; sample++) | |
510 { | |
511 if (++s->baud_phase >= 5) | |
512 { | |
513 s->baud_phase -= 5; | |
514 s->rrc_filter[s->rrc_filter_step] = | |
515 s->rrc_filter[s->rrc_filter_step + V27TER_TX_FILTER_STEPS] = getbaud(s); | |
516 if (++s->rrc_filter_step >= V27TER_TX_FILTER_STEPS) | |
517 s->rrc_filter_step = 0; | |
518 } | |
519 /* Root raised cosine pulse shaping at baseband */ | |
520 x.re = 0.0f; | |
521 x.im = 0.0f; | |
522 for (i = 0; i < V27TER_TX_FILTER_STEPS; i++) | |
523 { | |
524 x.re += pulseshaper_4800[4 - s->baud_phase][i]*s->rrc_filter[i + s->rrc_filter_step].re; | |
525 x.im += pulseshaper_4800[4 - s->baud_phase][i]*s->rrc_filter[i + s->rrc_filter_step].im; | |
526 } | |
527 /* Now create and modulate the carrier */ | |
528 z = dds_complexf(&(s->carrier_phase), s->carrier_phase_rate); | |
529 /* Don't bother saturating. We should never clip. */ | |
530 amp[sample] = (int16_t) lrintf((x.re*z.re - x.im*z.im)*s->gain_4800); | |
531 } | |
532 } | |
533 else | |
534 { | |
535 for (sample = 0; sample < len; sample++) | |
536 { | |
537 if ((s->baud_phase += 3) >= 20) | |
538 { | |
539 s->baud_phase -= 20; | |
540 s->rrc_filter[s->rrc_filter_step] = | |
541 s->rrc_filter[s->rrc_filter_step + V27TER_TX_FILTER_STEPS] = getbaud(s); | |
542 if (++s->rrc_filter_step >= V27TER_TX_FILTER_STEPS) | |
543 s->rrc_filter_step = 0; | |
544 } | |
545 /* Root raised cosine pulse shaping at baseband */ | |
546 x.re = 0.0f; | |
547 x.im = 0.0f; | |
548 for (i = 0; i < V27TER_TX_FILTER_STEPS; i++) | |
549 { | |
550 x.re += pulseshaper_2400[19 - s->baud_phase][i]*s->rrc_filter[i + s->rrc_filter_step].re; | |
551 x.im += pulseshaper_2400[19 - s->baud_phase][i]*s->rrc_filter[i + s->rrc_filter_step].im; | |
552 } | |
553 /* Now create and modulate the carrier */ | |
554 z = dds_complexf(&(s->carrier_phase), s->carrier_phase_rate); | |
555 /* Don't bother saturating. We should never clip. */ | |
556 amp[sample] = (int16_t) lrintf((x.re*z.re - x.im*z.im)*s->gain_2400); | |
557 } | |
558 } | |
559 return sample; | |
560 } | |
561 /*- End of function --------------------------------------------------------*/ | |
562 | |
563 void v27ter_tx_power(v27ter_tx_state_t *s, float power) | |
564 { | |
565 float l; | |
566 | |
567 l = powf(10.0f, (power - DBM0_MAX_POWER)/20.0f)*32768.0f; | |
568 s->gain_2400 = l/PULSESHAPER_2400_GAIN; | |
569 s->gain_4800 = l/PULSESHAPER_4800_GAIN; | |
570 } | |
571 /*- End of function --------------------------------------------------------*/ | |
572 | |
573 void v27ter_tx_set_get_bit(v27ter_tx_state_t *s, get_bit_func_t get_bit, void *user_data) | |
574 { | |
575 if (s->get_bit == s->current_get_bit) | |
576 s->current_get_bit = get_bit; | |
577 s->get_bit = get_bit; | |
578 s->user_data = user_data; | |
579 } | |
580 /*- End of function --------------------------------------------------------*/ | |
581 | |
582 int v27ter_tx_restart(v27ter_tx_state_t *s, int rate, int tep) | |
583 { | |
584 if (rate != 4800 && rate != 2400) | |
585 return -1; | |
586 s->bit_rate = rate; | |
587 cvec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0])); | |
588 s->rrc_filter_step = 0; | |
589 s->scramble_reg = 0x3C; | |
590 s->scrambler_pattern_count = 0; | |
591 s->in_training = TRUE; | |
592 s->training_step = (tep) ? V27TER_TRAINING_SEG_1 : V27TER_TRAINING_SEG_2; | |
593 s->carrier_phase = 0; | |
594 s->baud_phase = 0; | |
595 s->constellation_state = 0; | |
596 s->current_get_bit = fake_get_bit; | |
597 return 0; | |
598 } | |
599 /*- End of function --------------------------------------------------------*/ | |
600 | |
601 v27ter_tx_state_t *v27ter_tx_init(v27ter_tx_state_t *s, int rate, int tep, get_bit_func_t get_bit, void *user_data) | |
602 { | |
603 if (s == NULL) | |
604 { | |
605 if ((s = (v27ter_tx_state_t *) malloc(sizeof(*s))) == NULL) | |
606 return NULL; | |
607 } | |
608 memset(s, 0, sizeof(*s)); | |
609 s->get_bit = get_bit; | |
610 s->user_data = user_data; | |
611 s->carrier_phase_rate = dds_phase_ratef(CARRIER_NOMINAL_FREQ); | |
612 v27ter_tx_power(s, -14.0f); | |
613 v27ter_tx_restart(s, rate, tep); | |
614 return s; | |
615 } | |
616 /*- End of function --------------------------------------------------------*/ | |
617 | |
618 int v27ter_tx_release(v27ter_tx_state_t *s) | |
619 { | |
620 free(s); | |
621 return 0; | |
622 } | |
623 /*- End of function --------------------------------------------------------*/ | |
624 /*- End of file ------------------------------------------------------------*/ |