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 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
 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                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
 283storedigit:
 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}
 314