root/drivers/isdn/mISDN/dsp_dtmf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dsp_dtmf_goertzel_init
  2. dsp_dtmf_hardware
  3. dsp_dtmf_goertzel_decode

   1 /*
   2  * DTMF decoder.
   3  *
   4  * Copyright            by Andreas Eversberg (jolly@eversberg.eu)
   5  *                      based on different decoders such as ISDN4Linux
   6  *
   7  * This software may be used and distributed according to the terms
   8  * of the GNU General Public License, incorporated herein by reference.
   9  *
  10  */
  11 
  12 #include <linux/mISDNif.h>
  13 #include <linux/mISDNdsp.h>
  14 #include "core.h"
  15 #include "dsp.h"
  16 
  17 #define NCOEFF            8     /* number of frequencies to be analyzed */
  18 
  19 /* For DTMF recognition:
  20  * 2 * cos(2 * PI * k / N) precalculated for all k
  21  */
  22 static u64 cos2pik[NCOEFF] =
  23 {
  24         /* k << 15 (source: hfc-4s/8s documentation (www.colognechip.de)) */
  25         55960, 53912, 51402, 48438, 38146, 32650, 26170, 18630
  26 };
  27 
  28 /* digit matrix */
  29 static char dtmf_matrix[4][4] =
  30 {
  31         {'1', '2', '3', 'A'},
  32         {'4', '5', '6', 'B'},
  33         {'7', '8', '9', 'C'},
  34         {'*', '0', '#', 'D'}
  35 };
  36 
  37 /* dtmf detection using goertzel algorithm
  38  * init function
  39  */
  40 void dsp_dtmf_goertzel_init(struct dsp *dsp)
  41 {
  42         dsp->dtmf.size = 0;
  43         dsp->dtmf.lastwhat = '\0';
  44         dsp->dtmf.lastdigit = '\0';
  45         dsp->dtmf.count = 0;
  46 }
  47 
  48 /* check for hardware or software features
  49  */
  50 void dsp_dtmf_hardware(struct dsp *dsp)
  51 {
  52         int hardware = 1;
  53 
  54         if (!dsp->dtmf.enable)
  55                 return;
  56 
  57         if (!dsp->features.hfc_dtmf)
  58                 hardware = 0;
  59 
  60         /* check for volume change */
  61         if (dsp->tx_volume) {
  62                 if (dsp_debug & DEBUG_DSP_DTMF)
  63                         printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, "
  64                                "because tx_volume is changed\n",
  65                                __func__, dsp->name);
  66                 hardware = 0;
  67         }
  68         if (dsp->rx_volume) {
  69                 if (dsp_debug & DEBUG_DSP_DTMF)
  70                         printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, "
  71                                "because rx_volume is changed\n",
  72                                __func__, dsp->name);
  73                 hardware = 0;
  74         }
  75         /* check if encryption is enabled */
  76         if (dsp->bf_enable) {
  77                 if (dsp_debug & DEBUG_DSP_DTMF)
  78                         printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, "
  79                                "because encryption is enabled\n",
  80                                __func__, dsp->name);
  81                 hardware = 0;
  82         }
  83         /* check if pipeline exists */
  84         if (dsp->pipeline.inuse) {
  85                 if (dsp_debug & DEBUG_DSP_DTMF)
  86                         printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, "
  87                                "because pipeline exists.\n",
  88                                __func__, dsp->name);
  89                 hardware = 0;
  90         }
  91 
  92         dsp->dtmf.hardware = hardware;
  93         dsp->dtmf.software = !hardware;
  94 }
  95 
  96 
  97 /*************************************************************
  98  * calculate the coefficients of the given sample and decode *
  99  *************************************************************/
 100 
 101 /* the given sample is decoded. if the sample is not long enough for a
 102  * complete frame, the decoding is finished and continued with the next
 103  * call of this function.
 104  *
 105  * the algorithm is very good for detection with a minimum of errors. i
 106  * tested it allot. it even works with very short tones (40ms). the only
 107  * disadvantage is, that it doesn't work good with different volumes of both
 108  * tones. this will happen, if accoustically coupled dialers are used.
 109  * it sometimes detects tones during speech, which is normal for decoders.
 110  * use sequences to given commands during calls.
 111  *
 112  * dtmf - points to a structure of the current dtmf state
 113  * spl and len - the sample
 114  * fmt - 0 = alaw, 1 = ulaw, 2 = coefficients from HFC DTMF hw-decoder
 115  */
 116 
 117 u8
 118 *dsp_dtmf_goertzel_decode(struct dsp *dsp, u8 *data, int len, int fmt)
 119 {
 120         u8 what;
 121         int size;
 122         signed short *buf;
 123         s32 sk, sk1, sk2;
 124         int k, n, i;
 125         s32 *hfccoeff;
 126         s32 result[NCOEFF], tresh, treshl;
 127         int lowgroup, highgroup;
 128         s64 cos2pik_;
 129 
 130         dsp->dtmf.digits[0] = '\0';
 131 
 132         /* Note: The function will loop until the buffer has not enough samples
 133          * left to decode a full frame.
 134          */
 135 again:
 136         /* convert samples */
 137         size = dsp->dtmf.size;
 138         buf = dsp->dtmf.buffer;
 139         switch (fmt) {
 140         case 0: /* alaw */
 141         case 1: /* ulaw */
 142                 while (size < DSP_DTMF_NPOINTS && len) {
 143                         buf[size++] = dsp_audio_law_to_s32[*data++];
 144                         len--;
 145                 }
 146                 break;
 147 
 148         case 2: /* HFC coefficients */
 149         default:
 150                 if (len < 64) {
 151                         if (len > 0)
 152                                 printk(KERN_ERR "%s: coefficients have invalid "
 153                                        "size. (is=%d < must=%d)\n",
 154                                        __func__, len, 64);
 155                         return dsp->dtmf.digits;
 156                 }
 157                 hfccoeff = (s32 *)data;
 158                 for (k = 0; k < NCOEFF; k++) {
 159                         sk2 = (*hfccoeff++) >> 4;
 160                         sk = (*hfccoeff++) >> 4;
 161                         if (sk > 32767 || sk < -32767 || sk2 > 32767
 162                             || sk2 < -32767)
 163                                 printk(KERN_WARNING
 164                                        "DTMF-Detection overflow\n");
 165                         /* compute |X(k)|**2 */
 166                         result[k] =
 167                                 (sk * sk) -
 168                                 (((cos2pik[k] * sk) >> 15) * sk2) +
 169                                 (sk2 * sk2);
 170                 }
 171                 data += 64;
 172                 len -= 64;
 173                 goto coefficients;
 174                 break;
 175         }
 176         dsp->dtmf.size = size;
 177 
 178         if (size < DSP_DTMF_NPOINTS)
 179                 return dsp->dtmf.digits;
 180 
 181         dsp->dtmf.size = 0;
 182 
 183         /* now we have a full buffer of signed long samples - we do goertzel */
 184         for (k = 0; k < NCOEFF; k++) {
 185                 sk = 0;
 186                 sk1 = 0;
 187                 sk2 = 0;
 188                 buf = dsp->dtmf.buffer;
 189                 cos2pik_ = cos2pik[k];
 190                 for (n = 0; n < DSP_DTMF_NPOINTS; n++) {
 191                         sk = ((cos2pik_ * sk1) >> 15) - sk2 + (*buf++);
 192                         sk2 = sk1;
 193                         sk1 = sk;
 194                 }
 195                 sk >>= 8;
 196                 sk2 >>= 8;
 197                 if (sk > 32767 || sk < -32767 || sk2 > 32767 || sk2 < -32767)
 198                         printk(KERN_WARNING "DTMF-Detection overflow\n");
 199                 /* compute |X(k)|**2 */
 200                 result[k] =
 201                         (sk * sk) -
 202                         (((cos2pik[k] * sk) >> 15) * sk2) +
 203                         (sk2 * sk2);
 204         }
 205 
 206         /* our (squared) coefficients have been calculated, we need to process
 207          * them.
 208          */
 209 coefficients:
 210         tresh = 0;
 211         for (i = 0; i < NCOEFF; i++) {
 212                 if (result[i] < 0)
 213                         result[i] = 0;
 214                 if (result[i] > dsp->dtmf.treshold) {
 215                         if (result[i] > tresh)
 216                                 tresh = result[i];
 217                 }
 218         }
 219 
 220         if (tresh == 0) {
 221                 what = 0;
 222                 goto storedigit;
 223         }
 224 
 225         if (dsp_debug & DEBUG_DSP_DTMFCOEFF) {
 226                 s32 tresh_100 = tresh/100;
 227 
 228                 if (tresh_100 == 0) {
 229                         tresh_100 = 1;
 230                         printk(KERN_DEBUG
 231                                 "tresh(%d) too small set tresh/100 to 1\n",
 232                                 tresh);
 233                 }
 234                 printk(KERN_DEBUG "a %3d %3d %3d %3d %3d %3d %3d %3d"
 235                        " tr:%3d r %3d %3d %3d %3d %3d %3d %3d %3d\n",
 236                        result[0] / 10000, result[1] / 10000, result[2] / 10000,
 237                        result[3] / 10000, result[4] / 10000, result[5] / 10000,
 238                        result[6] / 10000, result[7] / 10000, tresh / 10000,
 239                        result[0] / (tresh_100), result[1] / (tresh_100),
 240                        result[2] / (tresh_100), result[3] / (tresh_100),
 241                        result[4] / (tresh_100), result[5] / (tresh_100),
 242                        result[6] / (tresh_100), result[7] / (tresh_100));
 243         }
 244 
 245         /* calc digit (lowgroup/highgroup) */
 246         lowgroup = -1;
 247         highgroup = -1;
 248         treshl = tresh >> 3;  /* tones which are not on, must be below 9 dB */
 249         tresh = tresh >> 2;  /* touchtones must match within 6 dB */
 250         for (i = 0; i < NCOEFF; i++) {
 251                 if (result[i] < treshl)
 252                         continue;  /* ignore */
 253                 if (result[i] < tresh) {
 254                         lowgroup = -1;
 255                         highgroup = -1;
 256                         break;  /* noise in between */
 257                 }
 258                 /* good level found. This is allowed only one time per group */
 259                 if (i < NCOEFF / 2) {
 260                         /* lowgroup */
 261                         if (lowgroup >= 0) {
 262                                 /* Bad. Another tone found. */
 263                                 lowgroup = -1;
 264                                 break;
 265                         } else
 266                                 lowgroup = i;
 267                 } else {
 268                         /* higroup */
 269                         if (highgroup >= 0) {
 270                                 /* Bad. Another tone found. */
 271                                 highgroup = -1;
 272                                 break;
 273                         } else
 274                                 highgroup = i - (NCOEFF / 2);
 275                 }
 276         }
 277 
 278         /* get digit or null */
 279         what = 0;
 280         if (lowgroup >= 0 && highgroup >= 0)
 281                 what = dtmf_matrix[lowgroup][highgroup];
 282 
 283 storedigit:
 284         if (what && (dsp_debug & DEBUG_DSP_DTMF))
 285                 printk(KERN_DEBUG "DTMF what: %c\n", what);
 286 
 287         if (dsp->dtmf.lastwhat != what)
 288                 dsp->dtmf.count = 0;
 289 
 290         /* the tone (or no tone) must remain 3 times without change */
 291         if (dsp->dtmf.count == 2) {
 292                 if (dsp->dtmf.lastdigit != what) {
 293                         dsp->dtmf.lastdigit = what;
 294                         if (what) {
 295                                 if (dsp_debug & DEBUG_DSP_DTMF)
 296                                         printk(KERN_DEBUG "DTMF digit: %c\n",
 297                                                what);
 298                                 if ((strlen(dsp->dtmf.digits) + 1)
 299                                     < sizeof(dsp->dtmf.digits)) {
 300                                         dsp->dtmf.digits[strlen(
 301                                                         dsp->dtmf.digits) + 1] = '\0';
 302                                         dsp->dtmf.digits[strlen(
 303                                                         dsp->dtmf.digits)] = what;
 304                                 }
 305                         }
 306                 }
 307         } else
 308                 dsp->dtmf.count++;
 309 
 310         dsp->dtmf.lastwhat = what;
 311 
 312         goto again;
 313 }

/* [<][>][^][v][top][bottom][index][help] */