dect
/
asterisk
Archived
13
0
Fork 0

Optionally build integer-based routines for FSK tone decoding (but default

to the more accurate float-based routines).
(Closes issue #11679)
(Step 1 of 2)


git-svn-id: http://svn.digium.com/svn/asterisk/trunk@132510 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
tilghman 2008-07-21 20:59:03 +00:00
parent b714462a52
commit 42899d3f85
7 changed files with 473 additions and 1 deletions

View File

@ -44,4 +44,6 @@
</member>
<member name="IAX_OLD_FIND" displayname="Use the old, slow method of searching for IAX callnos">
</member>
<member name="INTEGER_CALLERID" displayname="Use the (less accurate) integer-based method for decoding FSK tones (for embedded systems)">
</member>
</category>

View File

@ -0,0 +1,71 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
*
* 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 Modem Support
* \note Includes code and algorithms from the Zapata library.
*/
#ifndef _ASTERISK_FSKMODEM_H
#define _ASTERISK_FSKMODEM_H
#define PARITY_NONE 0
#define PARITY_EVEN 1
#define PARITY_ODD 2
#define NCOLA 0x4000
typedef struct {
float spb; /*!< Samples / Bit */
int nbit; /*!< Number of Data Bits (5,7,8) */
float nstop; /*!< Number of Stop Bits 1,1.5,2 */
int parity; /*!< Parity 0=none 1=even 2=odd */
int hdlc; /*!< Modo Packet */
float x0;
float x1;
float x2;
float cont;
int bw; /*!< Bandwidth */
double fmxv[8],fmyv[8]; /*!< filter stuff for M filter */
int fmp; /*!< pointer for M filter */
double fsxv[8],fsyv[8]; /*!< filter stuff for S filter */
int fsp; /*!< pointer for S filter */
double flxv[8],flyv[8]; /*!< filter stuff for L filter */
int flp; /*!< pointer for L filter */
int f_mark_idx; /*!< Mark frequency index (f_M-500)/5 */
int f_space_idx; /*!< Space frequency index (f_S-500)/5 */
int state;
int pcola; /*!< Pointer to data queues */
float cola_in[NCOLA]; /*!< Queue of input samples */
float cola_filter[NCOLA]; /*!< Queue of samples after filters */
float cola_demod[NCOLA]; /*!< Queue of demodulated samples */
} fsk_data;
/* \brief Retrieve a serial byte into outbyte.
Buffer is a pointer into a series of
shorts and len records the number of bytes in the buffer. len will be
overwritten with the number of bytes left that were not consumed.
\return return value is as follows:
\arg 0: Still looking for something...
\arg 1: An output byte was received and stored in outbyte
\arg -1: An error occured in the transmission
He must be called with at least 80 bytes of buffer. */
int fsk_serial(fsk_data *fskd, short *buffer, int *len, int *outbyte);
#endif /* _ASTERISK_FSKMODEM_H */

View File

@ -128,6 +128,7 @@ struct callerid_state *callerid_new(int cid_signalling)
struct callerid_state *cid;
if ((cid = ast_calloc(1, sizeof(*cid)))) {
#ifdef INTEGER_CALLERID
cid->fskd.ispb = 7; /* 1200 baud */
/* Set up for 1200 / 8000 freq *32 to allow ints */
cid->fskd.pllispb = (int)(8000 * 32 / 1200);
@ -155,6 +156,27 @@ struct callerid_state *callerid_new(int cid_signalling)
/* cid->pos = 0; */
fskmodem_init(&cid->fskd);
#else
cid->fskd.spb = 7.0; /* 1200 baud */
/* cid->fskd.hdlc = 0; */ /* Async */
cid->fskd.nbit = 8; /* 8 bits */
cid->fskd.nstop = 1.0; /* 1 stop bit */
/* cid->fskd.paridad = 0; */ /* No parity */
cid->fskd.bw = 1; /* Filter 800 Hz */
if (cid_signalling == 2) { /* v23 signalling */
cid->fskd.f_mark_idx = 4; /* 1300 Hz */
cid->fskd.f_space_idx = 5; /* 2100 Hz */
} else { /* Bell 202 signalling as default */
cid->fskd.f_mark_idx = 2; /* 1200 Hz */
cid->fskd.f_space_idx = 3; /* 2200 Hz */
}
/* cid->fskd.pcola = 0; */ /* No clue */
/* cid->fskd.cont = 0.0; */ /* Digital PLL reset */
/* cid->fskd.x0 = 0.0; */
/* cid->fskd.state = 0; */
cid->flags = CID_UNKNOWN_NAME | CID_UNKNOWN_NUMBER;
/* cid->pos = 0; */
#endif
}
return cid;

360
main/fskmodem_float.c Normal file
View File

@ -0,0 +1,360 @@
/*
* 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)
/*! \brief Coefficients for input filters
* Coefficients table, generated by program "mkfilter"
* mkfilter is part of the zapatatelephony.org distribution
* Format: coef[IDX_FREC][IDX_BW][IDX_COEF]
* IDX_COEF = 0 => 1/GAIN
* IDX_COEF = 1-6 => Coefficientes y[n]
*/
static double coef_in[NF][NBW][8] = {
{
{ 1.8229206611e-04,-7.8997325866e-01,2.2401819940e+00,-4.6751353581e+00,5.5080745712e+00,-5.0571565772e+00,2.6215820004e+00,0.0000000000e+00, },
{ 9.8532175289e-02,-5.6297236492e-02,3.3146713415e-01,-9.2239200436e-01,1.4844365184e+00,-2.0183258642e+00,2.0074154497e+00,0.0000000000e+00, },
},
{
{ 1.8229206610e-04,-7.8997325866e-01,7.7191410839e-01,-2.8075643964e+00,1.6948618347e+00,-3.0367273700e+00,9.0333559408e-01,0.0000000000e+00, } ,
{ 9.8531161839e-02,-5.6297236492e-02,1.1421579050e-01,-4.8122536483e-01,4.0121072432e-01,-7.4834487567e-01,6.9170822332e-01,0.0000000000e+00, },
},
{
{ 1.8229206611e-04,-7.8997325866e-01,2.9003821430e+00,-6.1082779024e+00,7.7169345751e+00,-6.6075999680e+00,3.3941838836e+00,0.0000000000e+00, },
{ 9.8539686961e-02,-5.6297236492e-02,4.2915323820e-01,-1.2609358633e+00,2.2399213250e+00,-2.9928879142e+00,2.5990173742e+00,0.0000000000e+00, },
},
{
{ 1.8229206610e-04,-7.8997325866e-01,-7.7191410839e-01,-2.8075643964e+00,-1.6948618347e+00,-3.0367273700e+00,-9.0333559408e-01,0.0000000000e+00, },
{ 9.8531161839e-02,-5.6297236492e-02,-1.1421579050e-01,-4.8122536483e-01,-4.0121072432e-01,-7.4834487567e-01,-6.9170822332e-01,0.0000000000e+00, },
},
{
{ 1.8229206611e-04,-7.8997325866e-01,2.5782298908e+00,-5.3629717478e+00,6.5890882172e+00,-5.8012914776e+00,3.0171839130e+00,0.0000000000e+00, },
{ 9.8534230718e-02,-5.6297236492e-02,3.8148618075e-01,-1.0848760410e+00,1.8441165168e+00,-2.4860666655e+00,2.3103384142e+00,0.0000000000e+00, },
},
{
{ 1.8229206610e-04,-7.8997325866e-01,-3.8715051001e-01,-2.6192408538e+00,-8.3977994034e-01,-2.8329897913e+00,-4.5306444352e-01,0.0000000000e+00, },
{ 9.8531160936e-02,-5.6297236492e-02,-5.7284484199e-02,-4.3673866734e-01,-1.9564766257e-01,-6.2028156584e-01,-3.4692356122e-01,0.0000000000e+00, },
},
};
/*! \brief Coefficients for output filter
* Coefficients table, generated by program "mkfilter"
* Format: coef[IDX_BW][IDX_COEF]
* IDX_COEF = 0 => 1/GAIN
* IDX_COEF = 1-6 => Coefficientes y[n]
*/
static double coef_out[NBW][8] = {
{ 1.3868644653e-08,-6.3283665042e-01,4.0895057217e+00,-1.1020074592e+01,1.5850766191e+01,-1.2835109292e+01,5.5477477340e+00,0.0000000000e+00, },
{ 3.1262119724e-03,-7.8390522307e-03,8.5209627801e-02,-4.0804129163e-01,1.1157139955e+00,-1.8767603680e+00,1.8916395224e+00,0.0000000000e+00, },
};
/*! Band-pass filter for MARK frequency */
static inline float filterM(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;
}
/*! Band-pass filter for SPACE frequency */
static inline float filterS(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;
}
/*! Low-pass filter for demodulated data */
static inline float filterL(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 demodulator(fsk_data *fskd, float *retval, float x)
{
float xS,xM;
fskd->cola_in[fskd->pcola] = x;
xS = filterS(fskd,x);
xM = filterM(fskd,x);
fskd->cola_filter[fskd->pcola] = xM-xS;
x = filterL(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)
{
/* This function implements a DPLL to synchronize with the 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 (demodulator(fskd, &x, GET_SAMPLE))
return -1;
if ((x * fskd->x0) < 0) { /* Transition */
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_serial(fsk_data *fskd, short *buffer, int *len, int *outbyte)
{
int a;
int i,j,n1,r;
int samples = 0;
int olen;
int beginlen=*len;
int beginlenx;
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;
}
/* We await for start bit */
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 (demodulator(zap,&x1)) return(-1);
for (;;) {
if (demodulator(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! */
beginlenx=beginlen; /* just to avoid unused war warnings */
if (demodulator(fskd, &fskd->x1, GET_SAMPLE))
return -1;
samples++;
for (;;) {
search_startbit2:
if (*len <= 0) {
fskd->state = STATE_SEARCH_STARTBIT2;
return 0;
}
samples++;
if (demodulator(fskd, &fskd->x2, GET_SAMPLE))
return(-1);
#if 0
printf("x2 = %5.5f ", fskd->x2);
#endif
if (fskd->x2 < -0.5)
break;
}
search_startbit3:
/* We await for 0.5 bits before using DPLL */
i = fskd->spb/2;
if (*len < i) {
fskd->state = STATE_SEARCH_STARTBIT3;
return 0;
}
for (; i>0; i--) {
if (demodulator(fskd, &fskd->x1, GET_SAMPLE))
return(-1);
#if 0
printf("x1 = %5.5f ", fskd->x1);
#endif
samples++;
}
/* x1 must be negative (start bit confirmation) */
} 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;
}
/* Now we read the data bits */
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;
/* We read parity bit (if exists) and check parity */
if (fskd->parity) {
olen = *len;
i = get_bit_raw(fskd, buffer, len);
buffer += (olen - *len);
if (i == -1)
return(-1);
if (i)
n1++;
if (fskd->parity == 1) { /* parity=1 (even) */
if (n1&1)
a |= 0x100; /* error */
} else { /* parity=2 (odd) */
if (!(n1&1))
a |= 0x100; /* error */
}
}
/* We read STOP bits. All of them must be 1 */
for (j = fskd->nstop;j;j--) {
r = get_bit_raw(fskd, buffer, len);
if (r == -1)
return(-1);
if (!r)
a |= 0x200;
}
/* And finally we return */
/* Bit 8 : Parity error */
/* Bit 9 : Framming error*/
*outbyte = a;
fskd->state = STATE_SEARCH_STARTBIT;
return 1;
}

View File

@ -99,6 +99,7 @@ struct tdd_state *tdd_new(void)
struct tdd_state *tdd;
tdd = calloc(1, sizeof(*tdd));
if (tdd) {
#ifdef INTEGER_CALLERID
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);
@ -115,8 +116,24 @@ struct tdd_state *tdd_new(void)
tdd->fskd.state = 0;
tdd->pos = 0;
tdd->mode = 0;
tdd->charnum = 0;
fskmodem_init(&tdd->fskd);
#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;
} else
ast_log(LOG_WARNING, "Out of memory\n");
return tdd;