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 Fri Feb 27 12:19:44 2004 for Asterisk by doxygen 1.3.5