Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

tdd.c

Go to the documentation of this file.
00001 /* 00002 * Asterisk -- A telephony toolkit for Linux. 00003 * 00004 * TTY/TDD Generation support 00005 * 00006 * Copyright (C) 2001, Linux Support Services, Inc. 00007 * 00008 * Mark Spencer <markster@linux-support.net> 00009 * 00010 * This program is free software, distributed under the terms of 00011 * the GNU General Public License. 00012 * 00013 * Includes code and algorithms from the Zapata library. 00014 * 00015 */ 00016 00017 #include <time.h> 00018 #include <string.h> 00019 #include <stdio.h> 00020 #include <stdlib.h> 00021 #include <unistd.h> 00022 #include <math.h> 00023 #include <ctype.h> 00024 #include <asterisk/ulaw.h> 00025 #include <asterisk/tdd.h> 00026 #include <asterisk/logger.h> 00027 #include <asterisk/fskmodem.h> 00028 #include "ecdisa.h" 00029 00030 00031 struct tdd_state { 00032 fsk_data fskd; 00033 char rawdata[256]; 00034 short oldstuff[4096]; 00035 int oldlen; 00036 int pos; 00037 int modo; 00038 int mode; 00039 }; 00040 00041 static float dr[4], di[4]; 00042 static float tddsb = 176.0; /* 45.5 baud */ 00043 00044 #define TDD_SPACE 1800.0 /* 1800 hz for "0" */ 00045 #define TDD_MARK 1400.0 /* 1400 hz for "1" */ 00046 00047 static int tdd_decode_baudot(struct tdd_state *tdd,unsigned char data) /* covert baudot into ASCII */ 00048 { 00049 static char ltrs[32]={'<','E','\n','A',' ','S','I','U', 00050 '\n','D','R','J','N','F','C','K', 00051 'T','Z','L','W','H','Y','P','Q', 00052 'O','B','G','^','M','X','V','^'}; 00053 static char figs[32]={'<','3','\n','-',' ',',','8','7', 00054 '\n','$','4','\'',',','·',':','(', 00055 '5','+',')','2','·','6','0','1', 00056 '9','7','·','^','.','/','=','^'}; 00057 int d; 00058 d=0; /* return 0 if not decodeable */ 00059 switch (data) { 00060 case 0x1f : tdd->modo=0; break; 00061 case 0x1b : tdd->modo=1; break; 00062 default: if (tdd->modo==0) d=ltrs[data]; else d=figs[data]; break; 00063 } 00064 return d; 00065 } 00066 00067 void tdd_init(void) 00068 { 00069 /* Initialize stuff for inverse FFT */ 00070 dr[0] = cos(TDD_SPACE * 2.0 * M_PI / 8000.0); 00071 di[0] = sin(TDD_SPACE * 2.0 * M_PI / 8000.0); 00072 dr[1] = cos(TDD_MARK * 2.0 * M_PI / 8000.0); 00073 di[1] = sin(TDD_MARK * 2.0 * M_PI / 8000.0); 00074 } 00075 00076 struct tdd_state *tdd_new(void) 00077 { 00078 struct tdd_state *tdd; 00079 tdd = malloc(sizeof(struct tdd_state)); 00080 memset(tdd, 0, sizeof(struct tdd_state)); 00081 if (tdd) { 00082 tdd->fskd.spb = 176; /* 45.5 baud */ 00083 tdd->fskd.hdlc = 0; /* Async */ 00084 tdd->fskd.nbit = 5; /* 5 bits */ 00085 tdd->fskd.nstop = 1.5; /* 1.5 stop bits */ 00086 tdd->fskd.paridad = 0; /* No parity */ 00087 tdd->fskd.bw=0; /* Filter 75 Hz */ 00088 tdd->fskd.f_mark_idx = 0; /* 1400 Hz */ 00089 tdd->fskd.f_space_idx = 1; /* 1800 Hz */ 00090 tdd->fskd.pcola = 0; /* No clue */ 00091 tdd->fskd.cont = 0; /* Digital PLL reset */ 00092 tdd->fskd.x0 = 0.0; 00093 tdd->fskd.state = 0; 00094 tdd->pos = 0; 00095 tdd->mode = 2; 00096 } else 00097 ast_log(LOG_WARNING, "Out of memory\n"); 00098 return tdd; 00099 } 00100 00101 int ast_tdd_gen_ecdisa(unsigned char *outbuf, int len) 00102 { 00103 int pos = 0; 00104 int cnt; 00105 while(len) { 00106 cnt = len; 00107 if (cnt > sizeof(ecdisa)) 00108 cnt = sizeof(ecdisa); 00109 memcpy(outbuf + pos, ecdisa, cnt); 00110 pos += cnt; 00111 len -= cnt; 00112 } 00113 return 0; 00114 } 00115 00116 int tdd_feed(struct tdd_state *tdd, unsigned char *ubuf, int len) 00117 { 00118 int mylen = len; 00119 int olen; 00120 int b = 'X'; 00121 int res; 00122 int c,x; 00123 short *buf = malloc(2 * len + tdd->oldlen); 00124 short *obuf = buf; 00125 if (!buf) { 00126 ast_log(LOG_WARNING, "Out of memory\n"); 00127 return -1; 00128 } 00129 memset(buf, 0, 2 * len + tdd->oldlen); 00130 memcpy(buf, tdd->oldstuff, tdd->oldlen); 00131 mylen += tdd->oldlen/2; 00132 for (x=0;x<len;x++) 00133 buf[x+tdd->oldlen/2] = AST_MULAW(ubuf[x]); 00134 c = res = 0; 00135 while(mylen >= 1320) { /* has to have enough to work on */ 00136 olen = mylen; 00137 res = fsk_serie(&tdd->fskd, buf, &mylen, &b); 00138 if (mylen < 0) { 00139 ast_log(LOG_ERROR, "fsk_serie made mylen < 0 (%d) (olen was %d)\n", mylen,olen); 00140 free(obuf); 00141 return -1; 00142 } 00143 buf += (olen - mylen); 00144 if (res < 0) { 00145 ast_log(LOG_NOTICE, "fsk_serie failed\n"); 00146 free(obuf); 00147 return -1; 00148 } 00149 if (res == 1) { 00150 /* Ignore invalid bytes */ 00151 if (b > 0x7f) 00152 continue; 00153 c = tdd_decode_baudot(tdd,b); 00154 if ((c < 1) || (c > 126)) continue; /* if not valid */ 00155 break; 00156 } 00157 } 00158 if (mylen) { 00159 memcpy(tdd->oldstuff, buf, mylen * 2); 00160 tdd->oldlen = mylen * 2; 00161 } else 00162 tdd->oldlen = 0; 00163 free(obuf); 00164 if (res) { 00165 tdd->mode = 2; /* put it in mode where it 00166 reliably puts teleprinter in correct shift mode */ 00167 return(c); 00168 } 00169 return 0; 00170 } 00171 00172 void tdd_free(struct tdd_state *tdd) 00173 { 00174 free(tdd); 00175 } 00176 00177 static inline float tdd_getcarrier(float *cr, float *ci, int bit) 00178 { 00179 /* Move along. There's nothing to see here... */ 00180 float t; 00181 t = *cr * dr[bit] - *ci * di[bit]; 00182 *ci = *cr * di[bit] + *ci * dr[bit]; 00183 *cr = t; 00184 00185 t = 2.0 - (*cr * *cr + *ci * *ci); 00186 *cr *= t; 00187 *ci *= t; 00188 return *cr; 00189 } 00190 00191 #define PUT_BYTE(a) do { \ 00192 *(buf++) = (a); \ 00193 bytes++; \ 00194 } while(0) 00195 00196 #define PUT_AUDIO_SAMPLE(y) do { \ 00197 int index = (short)(rint(8192.0 * (y))); \ 00198 *(buf++) = AST_LIN2MU(index); \ 00199 bytes++; \ 00200 } while(0) 00201 00202 #define PUT_TDD_MARKMS do { \ 00203 int x; \ 00204 for (x=0;x<8;x++) \ 00205 PUT_AUDIO_SAMPLE(tdd_getcarrier(&cr, &ci, 1)); \ 00206 } while(0) 00207 00208 #define PUT_TDD_BAUD(bit) do { \ 00209 while(scont < tddsb) { \ 00210 PUT_AUDIO_SAMPLE(tdd_getcarrier(&cr, &ci, bit)); \ 00211 scont += 1.0; \ 00212 } \ 00213 scont -= tddsb; \ 00214 } while(0) 00215 00216 #define PUT_TDD_STOP do { \ 00217 while(scont < (tddsb * 1.5)) { \ 00218 PUT_AUDIO_SAMPLE(tdd_getcarrier(&cr, &ci, 1)); \ 00219 scont += 1.0; \ 00220 } \ 00221 scont -= (tddsb * 1.5); \ 00222 } while(0) 00223 00224 00225 #define PUT_TDD(byte) do { \ 00226 int z; \ 00227 unsigned char b = (byte); \ 00228 PUT_TDD_BAUD(0); /* Start bit */ \ 00229 for (z=0;z<5;z++) { \ 00230 PUT_TDD_BAUD(b & 1); \ 00231 b >>= 1; \ 00232 } \ 00233 PUT_TDD_STOP; /* Stop bit */ \ 00234 } while(0); 00235 00236 int tdd_generate(struct tdd_state *tdd, unsigned char *buf, char *str) 00237 { 00238 int bytes=0; 00239 int i,x; 00240 char c; 00241 static unsigned char lstr[31] = "\000E\nA SIU\rDRJNFCKTZLWHYPQOBG\000MXV"; 00242 static unsigned char fstr[31] = "\0003\n- \00787\r$4',!:(5\")2\0006019?&\000./;"; 00243 /* Initial carriers (real/imaginary) */ 00244 float cr = 1.0; 00245 float ci = 0.0; 00246 float scont = 0.0; 00247 00248 for(x = 0; str[x]; x++) { 00249 c = toupper(str[x]); 00250 #if 0 00251 printf("%c",c); fflush(stdout); 00252 #endif 00253 if (c == 0) /* send null */ 00254 { 00255 PUT_TDD(0); 00256 continue; 00257 } 00258 if (c == '\r') /* send c/r */ 00259 { 00260 PUT_TDD(8); 00261 continue; 00262 } 00263 if (c == '\n') /* send c/r and l/f */ 00264 { 00265 PUT_TDD(8); 00266 PUT_TDD(2); 00267 continue; 00268 } 00269 if (c == ' ') /* send space */ 00270 { 00271 PUT_TDD(4); 00272 continue; 00273 } 00274 for(i = 0; i < 31; i++) 00275 { 00276 if (lstr[i] == c) break; 00277 } 00278 if (i < 31) /* if we found it */ 00279 { 00280 if (tdd->mode) /* if in figs mode, change it */ 00281 { 00282 PUT_TDD(31); /* Send LTRS */ 00283 tdd->mode = 0; 00284 } 00285 PUT_TDD(i); 00286 continue; 00287 } 00288 for(i = 0; i < 31; i++) 00289 { 00290 if (fstr[i] == c) break; 00291 } 00292 if (i < 31) /* if we found it */ 00293 { 00294 if (tdd->mode != 1) /* if in ltrs mode, change it */ 00295 { 00296 PUT_TDD(27); /* send FIGS */ 00297 tdd->mode = 1; 00298 } 00299 PUT_TDD(i); /* send byte */ 00300 continue; 00301 } 00302 } 00303 return bytes; 00304 } 00305 00306

Generated on Sat Jun 12 16:40:59 2004 for Asterisk by doxygen 1.3.7