| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * Copyright (C) 1999 - 2005, Digium, Inc. | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * Mark Spencer <markster@digium.com> | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Includes code and algorithms from the Zapata library. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * See http://www.asterisk.org for more information about
 | 
					
						
							|  |  |  |  * the Asterisk project. Please do not directly contact | 
					
						
							|  |  |  |  * any of the maintainers of this project for assistance; | 
					
						
							|  |  |  |  * the project provides a web site, mailing lists and IRC | 
					
						
							|  |  |  |  * channels for your use. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software, distributed under the terms of | 
					
						
							|  |  |  |  * the GNU General Public License Version 2. See the LICENSE file | 
					
						
							|  |  |  |  * at the top of the source tree. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-24 20:12:06 +00:00
										 |  |  | /*! \file
 | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-10-24 20:12:06 +00:00
										 |  |  |  * \brief TTY/TDD Generation support  | 
					
						
							| 
									
										
										
										
											2005-12-30 21:18:06 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * \author Mark Spencer <markster@digium.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \note Includes code and algorithms from the Zapata library. | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-07 18:54:56 +00:00
										 |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ASTERISK_FILE_VERSION(__FILE__, "$Revision$") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | #include <time.h>
 | 
					
						
							|  |  |  | #include <math.h>
 | 
					
						
							|  |  |  | #include <ctype.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-22 13:11:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-10-10 00:42:13 +00:00
										 |  |  | #include "asterisk/logger.h"
 | 
					
						
							| 
									
										
										
										
											2005-04-21 06:02:45 +00:00
										 |  |  | #include "asterisk/ulaw.h"
 | 
					
						
							|  |  |  | #include "asterisk/tdd.h"
 | 
					
						
							|  |  |  | #include "asterisk/fskmodem.h"
 | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | #include "ecdisa.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct tdd_state { | 
					
						
							|  |  |  | 	fsk_data fskd; | 
					
						
							|  |  |  | 	char rawdata[256]; | 
					
						
							|  |  |  | 	short oldstuff[4096]; | 
					
						
							|  |  |  | 	int oldlen; | 
					
						
							|  |  |  | 	int pos; | 
					
						
							|  |  |  | 	int modo; | 
					
						
							|  |  |  | 	int mode; | 
					
						
							| 
									
										
										
										
											2007-11-06 19:04:29 +00:00
										 |  |  | 	int charnum; | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static float dr[4], di[4]; | 
					
						
							|  |  |  | static float tddsb = 176.0;  /* 45.5 baud */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define TDD_SPACE	1800.0		/* 1800 hz for "0" */
 | 
					
						
							|  |  |  | #define TDD_MARK	1400.0		/* 1400 hz for "1" */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int tdd_decode_baudot(struct tdd_state *tdd,unsigned char data)	/* covert baudot into ASCII */ | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2006-07-10 19:05:48 +00:00
										 |  |  | 	static char ltrs[32] = { '<','E','\n','A',' ','S','I','U', | 
					
						
							|  |  |  | 	                         '\n','D','R','J','N','F','C','K', | 
					
						
							|  |  |  | 	                         'T','Z','L','W','H','Y','P','Q', | 
					
						
							|  |  |  | 	                         'O','B','G','^','M','X','V','^' }; | 
					
						
							| 
									
										
										
										
											2007-11-06 19:04:29 +00:00
										 |  |  | 	static char figs[32] = { '<','3','\n','-',' ','\'','8','7', | 
					
						
							|  |  |  | 	                         '\n','$','4','\'',',','!',':','(', | 
					
						
							|  |  |  | 	                         '5','\"',')','2','=','6','0','1', | 
					
						
							|  |  |  | 	                         '9','?','+','^','.','/',';','^' }; | 
					
						
							| 
									
										
										
										
											2006-07-10 19:05:48 +00:00
										 |  |  | 	int d = 0;  /* return 0 if not decodeable */ | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 	switch (data) { | 
					
						
							| 
									
										
										
										
											2006-07-10 19:05:48 +00:00
										 |  |  | 	case 0x1f: | 
					
						
							|  |  |  | 		tdd->modo = 0; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case 0x1b: | 
					
						
							|  |  |  | 		tdd->modo = 1; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		if (tdd->modo == 0) | 
					
						
							|  |  |  | 			d = ltrs[data]; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			d = figs[data]; | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return d; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void tdd_init(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* Initialize stuff for inverse FFT */ | 
					
						
							|  |  |  | 	dr[0] = cos(TDD_SPACE * 2.0 * M_PI / 8000.0); | 
					
						
							|  |  |  | 	di[0] = sin(TDD_SPACE * 2.0 * M_PI / 8000.0); | 
					
						
							|  |  |  | 	dr[1] = cos(TDD_MARK * 2.0 * M_PI / 8000.0); | 
					
						
							|  |  |  | 	di[1] = sin(TDD_MARK * 2.0 * M_PI / 8000.0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct tdd_state *tdd_new(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct tdd_state *tdd; | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 	tdd = calloc(1, sizeof(*tdd)); | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 	if (tdd) { | 
					
						
							| 
									
										
										
										
											2008-07-21 20:59:03 +00:00
										 |  |  | #ifdef INTEGER_CALLERID
 | 
					
						
							| 
									
										
										
										
											2007-08-06 19:52:40 +00:00
										 |  |  | 		tdd->fskd.ispb = 176;        /* 45.5 baud */ | 
					
						
							|  |  |  | 		/* Set up for 45.5 / 8000 freq *32 to allow ints */ | 
					
						
							|  |  |  | 		tdd->fskd.pllispb  = (int)((8000 * 32 * 2) / 90); | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  | 		tdd->fskd.pllids   = tdd->fskd.pllispb / 32; | 
					
						
							|  |  |  | 		tdd->fskd.pllispb2 = tdd->fskd.pllispb / 2; | 
					
						
							| 
									
										
										
										
											2006-07-10 19:05:48 +00:00
										 |  |  | 		tdd->fskd.hdlc = 0;         /* Async */ | 
					
						
							|  |  |  | 		tdd->fskd.nbit = 5;         /* 5 bits */ | 
					
						
							| 
									
										
										
										
											2007-08-06 19:52:40 +00:00
										 |  |  | 		tdd->fskd.instop = 1;       /* integer rep of 1.5 stop bits */ | 
					
						
							| 
									
										
										
										
											2006-12-05 20:15:37 +00:00
										 |  |  | 		tdd->fskd.parity = 0;       /* No parity */ | 
					
						
							| 
									
										
										
										
											2006-07-10 19:05:48 +00:00
										 |  |  | 		tdd->fskd.bw=0;             /* Filter 75 Hz */ | 
					
						
							|  |  |  | 		tdd->fskd.f_mark_idx = 0;   /* 1400 Hz */ | 
					
						
							|  |  |  | 		tdd->fskd.f_space_idx = 1;  /* 1800 Hz */ | 
					
						
							| 
									
										
										
										
											2007-08-06 19:52:40 +00:00
										 |  |  | 		tdd->fskd.xi0  = 0; | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 		tdd->fskd.state = 0; | 
					
						
							|  |  |  | 		tdd->pos = 0; | 
					
						
							| 
									
										
										
										
											2007-11-06 19:04:29 +00:00
										 |  |  | 		tdd->mode = 0; | 
					
						
							| 
									
										
										
										
											2007-08-06 19:52:40 +00:00
										 |  |  | 		fskmodem_init(&tdd->fskd); | 
					
						
							| 
									
										
										
										
											2008-07-21 20:59:03 +00:00
										 |  |  | #else
 | 
					
						
							|  |  |  | 		tdd->fskd.spb = 176;        /* 45.5 baud */ | 
					
						
							|  |  |  | 		tdd->fskd.hdlc = 0;         /* Async */ | 
					
						
							|  |  |  | 		tdd->fskd.nbit = 5;         /* 5 bits */ | 
					
						
							|  |  |  | 		tdd->fskd.nstop = 1.5;      /* 1.5 stop bits */ | 
					
						
							|  |  |  | 		tdd->fskd.parity = 0;       /* No parity */ | 
					
						
							|  |  |  | 		tdd->fskd.bw=0;             /* Filter 75 Hz */ | 
					
						
							|  |  |  | 		tdd->fskd.f_mark_idx = 0;   /* 1400 Hz */ | 
					
						
							|  |  |  | 		tdd->fskd.f_space_idx = 1;  /* 1800 Hz */ | 
					
						
							|  |  |  | 		tdd->fskd.pcola = 0;        /* No clue */ | 
					
						
							|  |  |  | 		tdd->fskd.cont = 0;         /* Digital PLL reset */ | 
					
						
							|  |  |  | 		tdd->fskd.x0 = 0.0; | 
					
						
							|  |  |  | 		tdd->fskd.state = 0; | 
					
						
							|  |  |  | 		tdd->pos = 0; | 
					
						
							|  |  |  | 		tdd->mode = 2; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 		tdd->charnum = 0; | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 	} else | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Out of memory\n"); | 
					
						
							|  |  |  | 	return tdd; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ast_tdd_gen_ecdisa(unsigned char *outbuf, int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int pos = 0; | 
					
						
							|  |  |  | 	int cnt; | 
					
						
							| 
									
										
										
										
											2006-07-10 19:05:48 +00:00
										 |  |  | 	while (len) { | 
					
						
							|  |  |  | 		cnt = len > sizeof(ecdisa) ? sizeof(ecdisa) : len; | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 		memcpy(outbuf + pos, ecdisa, cnt); | 
					
						
							|  |  |  | 		pos += cnt; | 
					
						
							|  |  |  | 		len -= cnt; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int tdd_feed(struct tdd_state *tdd, unsigned char *ubuf, int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int mylen = len; | 
					
						
							|  |  |  | 	int olen; | 
					
						
							|  |  |  | 	int b = 'X'; | 
					
						
							|  |  |  | 	int res; | 
					
						
							|  |  |  | 	int c,x; | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 	short *buf = calloc(1, 2 * len + tdd->oldlen); | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 	short *obuf = buf; | 
					
						
							|  |  |  | 	if (!buf) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Out of memory\n"); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	memcpy(buf, tdd->oldstuff, tdd->oldlen); | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  | 	mylen += tdd->oldlen / 2; | 
					
						
							| 
									
										
										
										
											2006-07-10 19:05:48 +00:00
										 |  |  | 	for (x = 0; x < len; x++)  | 
					
						
							|  |  |  | 		buf[x + tdd->oldlen / 2] = AST_MULAW(ubuf[x]); | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 	c = res = 0; | 
					
						
							| 
									
										
										
										
											2006-07-10 19:05:48 +00:00
										 |  |  | 	while (mylen >= 1320) { /* has to have enough to work on */ | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 		olen = mylen; | 
					
						
							| 
									
										
										
										
											2006-12-05 20:15:37 +00:00
										 |  |  | 		res = fsk_serial(&tdd->fskd, buf, &mylen, &b); | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 		if (mylen < 0) { | 
					
						
							| 
									
										
										
										
											2006-12-05 20:15:37 +00:00
										 |  |  | 			ast_log(LOG_ERROR, "fsk_serial made mylen < 0 (%d) (olen was %d)\n", mylen, olen); | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 			free(obuf); | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		buf += (olen - mylen); | 
					
						
							|  |  |  | 		if (res < 0) { | 
					
						
							| 
									
										
										
										
											2006-12-05 20:15:37 +00:00
										 |  |  | 			ast_log(LOG_NOTICE, "fsk_serial failed\n"); | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 			free(obuf); | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (res == 1) { | 
					
						
							|  |  |  | 			/* Ignore invalid bytes */ | 
					
						
							|  |  |  | 			if (b > 0x7f) | 
					
						
							|  |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  | 			c = tdd_decode_baudot(tdd, b); | 
					
						
							| 
									
										
										
										
											2006-12-02 13:40:13 +00:00
										 |  |  | 			if ((c < 1) || (c > 126)) | 
					
						
							|  |  |  | 				continue; /* if not valid */ | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (mylen) { | 
					
						
							|  |  |  | 		memcpy(tdd->oldstuff, buf, mylen * 2); | 
					
						
							|  |  |  | 		tdd->oldlen = mylen * 2; | 
					
						
							|  |  |  | 	} else | 
					
						
							|  |  |  | 		tdd->oldlen = 0; | 
					
						
							|  |  |  | 	free(obuf); | 
					
						
							| 
									
										
										
										
											2006-07-10 19:05:48 +00:00
										 |  |  | 	if (res) { | 
					
						
							| 
									
										
										
										
											2007-11-06 19:04:29 +00:00
										 |  |  | 		tdd->mode = 2;  | 
					
						
							|  |  |  | /* put it in mode where it
 | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 			reliably puts teleprinter in correct shift mode */ | 
					
						
							|  |  |  | 		return(c); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void tdd_free(struct tdd_state *tdd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	free(tdd); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline float tdd_getcarrier(float *cr, float *ci, int bit) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* Move along.  There's nothing to see here... */ | 
					
						
							|  |  |  | 	float t; | 
					
						
							|  |  |  | 	t = *cr * dr[bit] - *ci * di[bit]; | 
					
						
							|  |  |  | 	*ci = *cr * di[bit] + *ci * dr[bit]; | 
					
						
							|  |  |  | 	*cr = t; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	t = 2.0 - (*cr * *cr + *ci * *ci); | 
					
						
							|  |  |  | 	*cr *= t; | 
					
						
							|  |  |  | 	*ci *= t; | 
					
						
							|  |  |  | 	return *cr; | 
					
						
							|  |  |  | }	 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define PUT_BYTE(a) do { \
 | 
					
						
							|  |  |  | 	*(buf++) = (a); \ | 
					
						
							|  |  |  | 	bytes++; \ | 
					
						
							|  |  |  | } while(0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define PUT_AUDIO_SAMPLE(y) do { \
 | 
					
						
							| 
									
										
										
										
											2008-08-10 19:35:50 +00:00
										 |  |  | 	int __pas_idx = (short)(rint(8192.0 * (y))); \ | 
					
						
							|  |  |  | 	*(buf++) = AST_LIN2MU(__pas_idx); \ | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 	bytes++; \ | 
					
						
							|  |  |  | } while(0) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | #define PUT_TDD_MARKMS do { \
 | 
					
						
							|  |  |  | 	int x; \ | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  | 	for (x = 0; x < 8; x++) \ | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 		PUT_AUDIO_SAMPLE(tdd_getcarrier(&cr, &ci, 1)); \ | 
					
						
							|  |  |  | } while(0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define PUT_TDD_BAUD(bit) do { \
 | 
					
						
							| 
									
										
										
										
											2007-11-06 19:04:29 +00:00
										 |  |  | 	while (scont < tddsb) { \ | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 		PUT_AUDIO_SAMPLE(tdd_getcarrier(&cr, &ci, bit)); \ | 
					
						
							|  |  |  | 		scont += 1.0; \ | 
					
						
							|  |  |  | 	} \ | 
					
						
							|  |  |  | 	scont -= tddsb; \ | 
					
						
							|  |  |  | } while(0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define PUT_TDD_STOP do { \
 | 
					
						
							| 
									
										
										
										
											2007-11-06 19:04:29 +00:00
										 |  |  | 	while (scont < (tddsb * 1.5)) { \ | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 		PUT_AUDIO_SAMPLE(tdd_getcarrier(&cr, &ci, 1)); \ | 
					
						
							|  |  |  | 		scont += 1.0; \ | 
					
						
							|  |  |  | 	} \ | 
					
						
							|  |  |  | 	scont -= (tddsb * 1.5); \ | 
					
						
							|  |  |  | } while(0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define PUT_TDD(byte) do { \
 | 
					
						
							|  |  |  | 	int z; \ | 
					
						
							|  |  |  | 	unsigned char b = (byte); \ | 
					
						
							|  |  |  | 	PUT_TDD_BAUD(0); 	/* Start bit */ \ | 
					
						
							| 
									
										
										
										
											2006-07-10 19:05:48 +00:00
										 |  |  | 	for (z = 0; z < 5; z++) { \ | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 		PUT_TDD_BAUD(b & 1); \ | 
					
						
							|  |  |  | 		b >>= 1; \ | 
					
						
							|  |  |  | 	} \ | 
					
						
							|  |  |  | 	PUT_TDD_STOP;	/* Stop bit */ \ | 
					
						
							|  |  |  | } while(0);	 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-01 20:13:28 +00:00
										 |  |  | /*! Generate TDD hold tone
 | 
					
						
							|  |  |  |  * \param buf Result buffer | 
					
						
							|  |  |  |  * \todo How big should this be??? */ | 
					
						
							| 
									
										
										
										
											2007-11-06 19:10:26 +00:00
										 |  |  | int tdd_gen_holdtone(unsigned char *buf) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  | 	int bytes = 0; | 
					
						
							|  |  |  | 	float scont = 0.0, cr = 1.0, ci=0.0; | 
					
						
							|  |  |  | 	while (scont < tddsb * 10.0) { | 
					
						
							| 
									
										
										
										
											2007-11-06 19:10:26 +00:00
										 |  |  | 		PUT_AUDIO_SAMPLE(tdd_getcarrier(&cr, &ci, 1)); | 
					
						
							|  |  |  | 		scont += 1.0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return bytes; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-03-28 20:48:24 +00:00
										 |  |  | int tdd_generate(struct tdd_state *tdd, unsigned char *buf, const char *str) | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  | 	int bytes = 0; | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 	int i,x; | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  | 	char c; | 
					
						
							| 
									
										
										
										
											2006-12-15 13:36:34 +00:00
										 |  |  | 	/*! Baudot letters */ | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 	static unsigned char lstr[31] = "\000E\nA SIU\rDRJNFCKTZLWHYPQOBG\000MXV"; | 
					
						
							| 
									
										
										
										
											2006-12-15 13:36:34 +00:00
										 |  |  | 	/*! Baudot figures */ | 
					
						
							| 
									
										
										
										
											2007-11-06 19:04:29 +00:00
										 |  |  | 	static unsigned char fstr[31] = "\0003\n- \00787\r$4',!:(5\")2\0006019?+\000./;"; | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 	/* Initial carriers (real/imaginary) */ | 
					
						
							|  |  |  | 	float cr = 1.0; | 
					
						
							|  |  |  | 	float ci = 0.0; | 
					
						
							|  |  |  | 	float scont = 0.0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for(x = 0; str[x]; x++) { | 
					
						
							| 
									
										
										
										
											2007-11-06 19:04:29 +00:00
										 |  |  | 		/* Do synch for each 72th character */ | 
					
						
							|  |  |  | 		if ( (tdd->charnum++) % 72 == 0)  | 
					
						
							|  |  |  | 			PUT_TDD(tdd->mode ? 27 /* FIGS */ : 31 /* LTRS */); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 		c = toupper(str[x]); | 
					
						
							|  |  |  | #if	0
 | 
					
						
							|  |  |  | 		printf("%c",c); fflush(stdout); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2006-07-10 19:05:48 +00:00
										 |  |  | 		if (c == 0) { /* send null */ | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 			PUT_TDD(0); | 
					
						
							|  |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2006-07-10 19:05:48 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if (c == '\r') { /* send c/r */ | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 			PUT_TDD(8); | 
					
						
							|  |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2006-07-10 19:05:48 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if (c == '\n') { /* send c/r and l/f */ | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 			PUT_TDD(8); | 
					
						
							|  |  |  | 			PUT_TDD(2); | 
					
						
							|  |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2006-07-10 19:05:48 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if (c == ' ') { /* send space */ | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 			PUT_TDD(4); | 
					
						
							|  |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2006-07-10 19:05:48 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		for (i = 0; i < 31; i++) { | 
					
						
							|  |  |  | 			if (lstr[i] == c) | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (i < 31) {        /* if we found it */ | 
					
						
							|  |  |  | 			if (tdd->mode) { /* if in figs mode, change it */ | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 				PUT_TDD(31); /* Send LTRS */ | 
					
						
							|  |  |  | 				tdd->mode = 0; | 
					
						
							| 
									
										
										
										
											2006-07-10 19:05:48 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 			PUT_TDD(i); | 
					
						
							|  |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2006-07-10 19:05:48 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		for (i = 0; i < 31; i++) { | 
					
						
							|  |  |  | 			if (fstr[i] == c) | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (i < 31) {             /* if we found it */ | 
					
						
							|  |  |  | 			if (tdd->mode != 1) { /* if in ltrs mode, change it */ | 
					
						
							|  |  |  | 				PUT_TDD(27);      /* send FIGS */ | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 				tdd->mode = 1; | 
					
						
							| 
									
										
										
										
											2006-07-10 19:05:48 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			PUT_TDD(i);           /* send byte */ | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2006-07-10 19:05:48 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2001-12-07 22:57:34 +00:00
										 |  |  | 	return bytes; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 |