linux/drivers/isdn/mISDN/dsp_dtmf.c
<<
>>
Prefs
   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 */
  22static 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 */
  29static 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 */
  40void 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 */
  50void 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 speach, 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
 117u8
 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         */
 135again:
 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         */
 209coefficients:
 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                printk(KERN_DEBUG "a %3d %3d %3d %3d %3d %3d %3d %3d"
 227                        " tr:%3d r %3d %3d %3d %3d %3d %3d %3d %3d\n",
 228                        result[0]/10000, result[1]/10000, result[2]/10000,
 229                        result[3]/10000, result[4]/10000, result[5]/10000,
 230                        result[6]/10000, result[7]/10000, tresh/10000,
 231                        result[0]/(tresh/100), result[1]/(tresh/100),
 232                        result[2]/(tresh/100), result[3]/(tresh/100),
 233                        result[4]/(tresh/100), result[5]/(tresh/100),
 234                        result[6]/(tresh/100), result[7]/(tresh/100));
 235
 236        /* calc digit (lowgroup/highgroup) */
 237        lowgroup = -1;
 238        highgroup = -1;
 239        treshl = tresh >> 3;  /* tones which are not on, must be below 9 dB */
 240        tresh = tresh >> 2;  /* touchtones must match within 6 dB */
 241        for (i = 0; i < NCOEFF; i++) {
 242                if (result[i] < treshl)
 243                        continue;  /* ignore */
 244                if (result[i] < tresh) {
 245                        lowgroup = -1;
 246                        highgroup = -1;
 247                        break;  /* noise inbetween */
 248                }
 249                /* good level found. This is allowed only one time per group */
 250                if (i < NCOEFF/2) {
 251                        /* lowgroup */
 252                        if (lowgroup >= 0) {
 253                                /* Bad. Another tone found. */
 254                                lowgroup = -1;
 255                                break;
 256                        } else
 257                                lowgroup = i;
 258                } else {
 259                        /* higroup */
 260                        if (highgroup >= 0) {
 261                                /* Bad. Another tone found. */
 262                                highgroup = -1;
 263                                break;
 264                        } else
 265                                highgroup = i-(NCOEFF/2);
 266                }
 267        }
 268
 269        /* get digit or null */
 270        what = 0;
 271        if (lowgroup >= 0 && highgroup >= 0)
 272                what = dtmf_matrix[lowgroup][highgroup];
 273
 274storedigit:
 275        if (what && (dsp_debug & DEBUG_DSP_DTMF))
 276                printk(KERN_DEBUG "DTMF what: %c\n", what);
 277
 278        if (dsp->dtmf.lastwhat != what)
 279                dsp->dtmf.count = 0;
 280
 281        /* the tone (or no tone) must remain 3 times without change */
 282        if (dsp->dtmf.count == 2) {
 283                if (dsp->dtmf.lastdigit != what) {
 284                        dsp->dtmf.lastdigit = what;
 285                        if (what) {
 286                                if (dsp_debug & DEBUG_DSP_DTMF)
 287                                        printk(KERN_DEBUG "DTMF digit: %c\n",
 288                                                what);
 289                                if ((strlen(dsp->dtmf.digits)+1)
 290                                        < sizeof(dsp->dtmf.digits)) {
 291                                        dsp->dtmf.digits[strlen(
 292                                                dsp->dtmf.digits)+1] = '\0';
 293                                        dsp->dtmf.digits[strlen(
 294                                                dsp->dtmf.digits)] = what;
 295                                }
 296                        }
 297                }
 298        } else
 299                dsp->dtmf.count++;
 300
 301        dsp->dtmf.lastwhat = what;
 302
 303        goto again;
 304}
 305
 306
 307