diff options
author | kpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-08-21 02:11:39 +0000 |
---|---|---|
committer | kpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-08-21 02:11:39 +0000 |
commit | 8b0c007ad990aa27d9868da49215fd1076ac77cc (patch) | |
tree | 270b9c46c1e644483d6d2a35b509f43218ba3252 /main/fskmodem.c | |
parent | a42edc84034f91932a3e12d503e07f76a6eb498a (diff) |
merge new_loader_completion branch, including (at least):
- restructured build tree and makefiles to eliminate recursion problems
- support for embedded modules
- support for static builds
- simpler cross-compilation support
- simpler module/loader interface (no exported symbols)
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@40722 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'main/fskmodem.c')
-rw-r--r-- | main/fskmodem.c | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/main/fskmodem.c b/main/fskmodem.c new file mode 100644 index 000000000..9bbb2203f --- /dev/null +++ b/main/fskmodem.c @@ -0,0 +1,305 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 1999 - 2005, Digium, Inc. + * + * Mark Spencer <markster@digium.com> + * + * Includes code and algorithms from the Zapata library. + * + * 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. + */ + +/*! \file + * + * \brief FSK Modulator/Demodulator + * + * \author Mark Spencer <markster@digium.com> + * + * \arg Includes code and algorithms from the Zapata library. + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdio.h> + +#include "asterisk/fskmodem.h" + +#define NBW 2 +#define BWLIST {75,800} +#define NF 6 +#define FLIST {1400,1800,1200,2200,1300,2100} + +#define STATE_SEARCH_STARTBIT 0 +#define STATE_SEARCH_STARTBIT2 1 +#define STATE_SEARCH_STARTBIT3 2 +#define STATE_GET_BYTE 3 + +static inline float get_sample(short **buffer, int *len) +{ + float retval; + retval = (float) **buffer / 256; + (*buffer)++; + (*len)--; + return retval; +} + +#define GET_SAMPLE get_sample(&buffer, len) + +/* Coeficientes para filtros de entrada */ +/* Tabla de coeficientes, generada a partir del programa "mkfilter" */ +/* Formato: coef[IDX_FREC][IDX_BW][IDX_COEF] */ +/* IDX_COEF=0 => 1/GAIN */ +/* IDX_COEF=1-6 => Coeficientes y[n] */ + +static double coef_in[NF][NBW][8]={ +#include "coef_in.h" +}; + +/* Coeficientes para filtro de salida */ +/* Tabla de coeficientes, generada a partir del programa "mkfilter" */ +/* Formato: coef[IDX_BW][IDX_COEF] */ +/* IDX_COEF=0 => 1/GAIN */ +/* IDX_COEF=1-6 => Coeficientes y[n] */ + +static double coef_out[NBW][8]={ +#include "coef_out.h" +}; + + +/*! Filtro pasa-banda para frecuencia de MARCA */ +static inline float filtroM(fsk_data *fskd,float in) +{ + int i,j; + double s; + double *pc; + + pc=&coef_in[fskd->f_mark_idx][fskd->bw][0]; + fskd->fmxv[(fskd->fmp+6)&7]=in*(*pc++); + + s=(fskd->fmxv[(fskd->fmp+6)&7] - fskd->fmxv[fskd->fmp]) + 3 * (fskd->fmxv[(fskd->fmp+2)&7] - fskd->fmxv[(fskd->fmp+4)&7]); + for (i=0,j=fskd->fmp;i<6;i++,j++) s+=fskd->fmyv[j&7]*(*pc++); + fskd->fmyv[j&7]=s; + fskd->fmp++; fskd->fmp&=7; + return s; +} + +/*! Filtro pasa-banda para frecuencia de ESPACIO */ +static inline float filtroS(fsk_data *fskd,float in) +{ + int i,j; + double s; + double *pc; + + pc=&coef_in[fskd->f_space_idx][fskd->bw][0]; + fskd->fsxv[(fskd->fsp+6)&7]=in*(*pc++); + + s=(fskd->fsxv[(fskd->fsp+6)&7] - fskd->fsxv[fskd->fsp]) + 3 * (fskd->fsxv[(fskd->fsp+2)&7] - fskd->fsxv[(fskd->fsp+4)&7]); + for (i=0,j=fskd->fsp;i<6;i++,j++) s+=fskd->fsyv[j&7]*(*pc++); + fskd->fsyv[j&7]=s; + fskd->fsp++; fskd->fsp&=7; + return s; +} + +/*! Filtro pasa-bajos para datos demodulados */ +static inline float filtroL(fsk_data *fskd,float in) +{ + int i,j; + double s; + double *pc; + + pc=&coef_out[fskd->bw][0]; + fskd->flxv[(fskd->flp + 6) & 7]=in * (*pc++); + + s= (fskd->flxv[fskd->flp] + fskd->flxv[(fskd->flp+6)&7]) + + 6 * (fskd->flxv[(fskd->flp+1)&7] + fskd->flxv[(fskd->flp+5)&7]) + + 15 * (fskd->flxv[(fskd->flp+2)&7] + fskd->flxv[(fskd->flp+4)&7]) + + 20 * fskd->flxv[(fskd->flp+3)&7]; + + for (i=0,j=fskd->flp;i<6;i++,j++) s+=fskd->flyv[j&7]*(*pc++); + fskd->flyv[j&7]=s; + fskd->flp++; fskd->flp&=7; + return s; +} + +static inline int demodulador(fsk_data *fskd, float *retval, float x) +{ + float xS,xM; + + fskd->cola_in[fskd->pcola]=x; + + xS=filtroS(fskd,x); + xM=filtroM(fskd,x); + + fskd->cola_filtro[fskd->pcola]=xM-xS; + + x=filtroL(fskd,xM*xM - xS*xS); + + fskd->cola_demod[fskd->pcola++]=x; + fskd->pcola &= (NCOLA-1); + + *retval = x; + return(0); +} + +static int get_bit_raw(fsk_data *fskd, short *buffer, int *len) +{ + /* Esta funcion implementa un DPLL para sincronizarse con los bits */ + float x,spb,spb2,ds; + int f; + + spb=fskd->spb; + if (fskd->spb == 7) spb = 8000.0 / 1200.0; + ds=spb/32.; + spb2=spb/2.; + + for (f=0;;){ + if (demodulador(fskd,&x, GET_SAMPLE)) return(-1); + if ((x*fskd->x0)<0) { /* Transicion */ + if (!f) { + if (fskd->cont<(spb2)) fskd->cont+=ds; else fskd->cont-=ds; + f=1; + } + } + fskd->x0=x; + fskd->cont+=1.; + if (fskd->cont>spb) { + fskd->cont-=spb; + break; + } + } + f=(x>0)?0x80:0; + return(f); +} + +int fsk_serie(fsk_data *fskd, short *buffer, int *len, int *outbyte) +{ + int a; + int i,j,n1,r; + int samples=0; + int olen; + switch(fskd->state) { + /* Pick up where we left off */ + case STATE_SEARCH_STARTBIT2: + goto search_startbit2; + case STATE_SEARCH_STARTBIT3: + goto search_startbit3; + case STATE_GET_BYTE: + goto getbyte; + } + /* Esperamos bit de start */ + do { +/* this was jesus's nice, reasonable, working (at least with RTTY) code +to look for the beginning of the start bit. Unfortunately, since TTY/TDD's +just start sending a start bit with nothing preceding it at the beginning +of a transmission (what a LOSING design), we cant do it this elegantly */ +/* + if (demodulador(zap,&x1)) return(-1); + for(;;) { + if (demodulador(zap,&x2)) return(-1); + if (x1>0 && x2<0) break; + x1=x2; + } +*/ +/* this is now the imprecise, losing, but functional code to detect the +beginning of a start bit in the TDD sceanario. It just looks for sufficient +level to maybe, perhaps, guess, maybe that its maybe the beginning of +a start bit, perhaps. This whole thing stinks! */ + if (demodulador(fskd,&fskd->x1,GET_SAMPLE)) return(-1); + samples++; + for(;;) + { +search_startbit2: + if (!*len) { + fskd->state = STATE_SEARCH_STARTBIT2; + return 0; + } + samples++; + if (demodulador(fskd,&fskd->x2,GET_SAMPLE)) return(-1); +#if 0 + printf("x2 = %5.5f ", fskd->x2); +#endif + if (fskd->x2 < -0.5) break; + } +search_startbit3: + /* Esperamos 0.5 bits antes de usar DPLL */ + i=fskd->spb/2; + if (*len < i) { + fskd->state = STATE_SEARCH_STARTBIT3; + return 0; + } + for(;i;i--) { if (demodulador(fskd,&fskd->x1,GET_SAMPLE)) return(-1); +#if 0 + printf("x1 = %5.5f ", fskd->x1); +#endif + samples++; } + + /* x1 debe ser negativo (confirmación del bit de start) */ + + } while (fskd->x1>0); + fskd->state = STATE_GET_BYTE; + +getbyte: + + /* Need at least 80 samples (for 1200) or + 1320 (for 45.5) to be sure we'll have a byte */ + if (fskd->nbit < 8) { + if (*len < 1320) + return 0; + } else { + if (*len < 80) + return 0; + } + /* Leemos ahora los bits de datos */ + j=fskd->nbit; + for (a=n1=0;j;j--) { + olen = *len; + i=get_bit_raw(fskd, buffer, len); + buffer += (olen - *len); + if (i == -1) return(-1); + if (i) n1++; + a>>=1; a|=i; + } + j=8-fskd->nbit; + a>>=j; + + /* Leemos bit de paridad (si existe) y la comprobamos */ + if (fskd->paridad) { + olen = *len; + i=get_bit_raw(fskd, buffer, len); + buffer += (olen - *len); + if (i == -1) return(-1); + if (i) n1++; + if (fskd->paridad==1) { /* paridad=1 (par) */ + if (n1&1) a|=0x100; /* error */ + } else { /* paridad=2 (impar) */ + if (!(n1&1)) a|=0x100; /* error */ + } + } + + /* Leemos bits de STOP. Todos deben ser 1 */ + + for (j=fskd->nstop;j;j--) { + r = get_bit_raw(fskd, buffer, len); + if (r == -1) return(-1); + if (!r) a|=0x200; + } + + /* Por fin retornamos */ + /* Bit 8 : Error de paridad */ + /* Bit 9 : Error de Framming */ + + *outbyte = a; + fskd->state = STATE_SEARCH_STARTBIT; + return 1; +} |