1960366cfSKarsten Keil /* 2960366cfSKarsten Keil * DTMF decoder. 3960366cfSKarsten Keil * 4960366cfSKarsten Keil * Copyright by Andreas Eversberg (jolly@eversberg.eu) 5960366cfSKarsten Keil * based on different decoders such as ISDN4Linux 6960366cfSKarsten Keil * 7960366cfSKarsten Keil * This software may be used and distributed according to the terms 8960366cfSKarsten Keil * of the GNU General Public License, incorporated herein by reference. 9960366cfSKarsten Keil * 10960366cfSKarsten Keil */ 11960366cfSKarsten Keil 12960366cfSKarsten Keil #include <linux/mISDNif.h> 13960366cfSKarsten Keil #include <linux/mISDNdsp.h> 14960366cfSKarsten Keil #include "core.h" 15960366cfSKarsten Keil #include "dsp.h" 16960366cfSKarsten Keil 17960366cfSKarsten Keil #define NCOEFF 8 /* number of frequencies to be analyzed */ 18960366cfSKarsten Keil 19960366cfSKarsten Keil /* For DTMF recognition: 20960366cfSKarsten Keil * 2 * cos(2 * PI * k / N) precalculated for all k 21960366cfSKarsten Keil */ 22960366cfSKarsten Keil static u64 cos2pik[NCOEFF] = 23960366cfSKarsten Keil { 24960366cfSKarsten Keil /* k << 15 (source: hfc-4s/8s documentation (www.colognechip.de)) */ 25960366cfSKarsten Keil 55960, 53912, 51402, 48438, 38146, 32650, 26170, 18630 26960366cfSKarsten Keil }; 27960366cfSKarsten Keil 28960366cfSKarsten Keil /* digit matrix */ 29960366cfSKarsten Keil static char dtmf_matrix[4][4] = 30960366cfSKarsten Keil { 31960366cfSKarsten Keil {'1', '2', '3', 'A'}, 32960366cfSKarsten Keil {'4', '5', '6', 'B'}, 33960366cfSKarsten Keil {'7', '8', '9', 'C'}, 34960366cfSKarsten Keil {'*', '0', '#', 'D'} 35960366cfSKarsten Keil }; 36960366cfSKarsten Keil 37960366cfSKarsten Keil /* dtmf detection using goertzel algorithm 38960366cfSKarsten Keil * init function 39960366cfSKarsten Keil */ 40960366cfSKarsten Keil void dsp_dtmf_goertzel_init(struct dsp *dsp) 41960366cfSKarsten Keil { 42960366cfSKarsten Keil dsp->dtmf.size = 0; 43960366cfSKarsten Keil dsp->dtmf.lastwhat = '\0'; 44960366cfSKarsten Keil dsp->dtmf.lastdigit = '\0'; 45960366cfSKarsten Keil dsp->dtmf.count = 0; 46960366cfSKarsten Keil } 47960366cfSKarsten Keil 48960366cfSKarsten Keil /* check for hardware or software features 49960366cfSKarsten Keil */ 50960366cfSKarsten Keil void dsp_dtmf_hardware(struct dsp *dsp) 51960366cfSKarsten Keil { 52960366cfSKarsten Keil int hardware = 1; 53960366cfSKarsten Keil 54b0579d74SAndreas Eversberg if (!dsp->dtmf.enable) 55b0579d74SAndreas Eversberg return; 56b0579d74SAndreas Eversberg 57960366cfSKarsten Keil if (!dsp->features.hfc_dtmf) 58960366cfSKarsten Keil hardware = 0; 59960366cfSKarsten Keil 60960366cfSKarsten Keil /* check for volume change */ 61960366cfSKarsten Keil if (dsp->tx_volume) { 62960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_DTMF) 63960366cfSKarsten Keil printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " 64960366cfSKarsten Keil "because tx_volume is changed\n", 65960366cfSKarsten Keil __func__, dsp->name); 66960366cfSKarsten Keil hardware = 0; 67960366cfSKarsten Keil } 68960366cfSKarsten Keil if (dsp->rx_volume) { 69960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_DTMF) 70960366cfSKarsten Keil printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " 71960366cfSKarsten Keil "because rx_volume is changed\n", 72960366cfSKarsten Keil __func__, dsp->name); 73960366cfSKarsten Keil hardware = 0; 74960366cfSKarsten Keil } 75960366cfSKarsten Keil /* check if encryption is enabled */ 76960366cfSKarsten Keil if (dsp->bf_enable) { 77960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_DTMF) 78960366cfSKarsten Keil printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " 79960366cfSKarsten Keil "because encryption is enabled\n", 80960366cfSKarsten Keil __func__, dsp->name); 81960366cfSKarsten Keil hardware = 0; 82960366cfSKarsten Keil } 83960366cfSKarsten Keil /* check if pipeline exists */ 84960366cfSKarsten Keil if (dsp->pipeline.inuse) { 85960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_DTMF) 86960366cfSKarsten Keil printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " 87960366cfSKarsten Keil "because pipeline exists.\n", 88960366cfSKarsten Keil __func__, dsp->name); 89960366cfSKarsten Keil hardware = 0; 90960366cfSKarsten Keil } 91960366cfSKarsten Keil 92960366cfSKarsten Keil dsp->dtmf.hardware = hardware; 93960366cfSKarsten Keil dsp->dtmf.software = !hardware; 94960366cfSKarsten Keil } 95960366cfSKarsten Keil 96960366cfSKarsten Keil 97960366cfSKarsten Keil /************************************************************* 98960366cfSKarsten Keil * calculate the coefficients of the given sample and decode * 99960366cfSKarsten Keil *************************************************************/ 100960366cfSKarsten Keil 101960366cfSKarsten Keil /* the given sample is decoded. if the sample is not long enough for a 102960366cfSKarsten Keil * complete frame, the decoding is finished and continued with the next 103960366cfSKarsten Keil * call of this function. 104960366cfSKarsten Keil * 105960366cfSKarsten Keil * the algorithm is very good for detection with a minimum of errors. i 106960366cfSKarsten Keil * tested it allot. it even works with very short tones (40ms). the only 107960366cfSKarsten Keil * disadvantage is, that it doesn't work good with different volumes of both 108960366cfSKarsten Keil * tones. this will happen, if accoustically coupled dialers are used. 109*25985edcSLucas De Marchi * it sometimes detects tones during speech, which is normal for decoders. 110960366cfSKarsten Keil * use sequences to given commands during calls. 111960366cfSKarsten Keil * 112960366cfSKarsten Keil * dtmf - points to a structure of the current dtmf state 113960366cfSKarsten Keil * spl and len - the sample 114960366cfSKarsten Keil * fmt - 0 = alaw, 1 = ulaw, 2 = coefficients from HFC DTMF hw-decoder 115960366cfSKarsten Keil */ 116960366cfSKarsten Keil 117960366cfSKarsten Keil u8 118960366cfSKarsten Keil *dsp_dtmf_goertzel_decode(struct dsp *dsp, u8 *data, int len, int fmt) 119960366cfSKarsten Keil { 120960366cfSKarsten Keil u8 what; 121960366cfSKarsten Keil int size; 122960366cfSKarsten Keil signed short *buf; 123960366cfSKarsten Keil s32 sk, sk1, sk2; 124960366cfSKarsten Keil int k, n, i; 125960366cfSKarsten Keil s32 *hfccoeff; 126960366cfSKarsten Keil s32 result[NCOEFF], tresh, treshl; 127960366cfSKarsten Keil int lowgroup, highgroup; 128960366cfSKarsten Keil s64 cos2pik_; 129960366cfSKarsten Keil 130960366cfSKarsten Keil dsp->dtmf.digits[0] = '\0'; 131960366cfSKarsten Keil 132960366cfSKarsten Keil /* Note: The function will loop until the buffer has not enough samples 133960366cfSKarsten Keil * left to decode a full frame. 134960366cfSKarsten Keil */ 135960366cfSKarsten Keil again: 136960366cfSKarsten Keil /* convert samples */ 137960366cfSKarsten Keil size = dsp->dtmf.size; 138960366cfSKarsten Keil buf = dsp->dtmf.buffer; 139960366cfSKarsten Keil switch (fmt) { 140960366cfSKarsten Keil case 0: /* alaw */ 141960366cfSKarsten Keil case 1: /* ulaw */ 142960366cfSKarsten Keil while (size < DSP_DTMF_NPOINTS && len) { 143960366cfSKarsten Keil buf[size++] = dsp_audio_law_to_s32[*data++]; 144960366cfSKarsten Keil len--; 145960366cfSKarsten Keil } 146960366cfSKarsten Keil break; 147960366cfSKarsten Keil 148960366cfSKarsten Keil case 2: /* HFC coefficients */ 149960366cfSKarsten Keil default: 150960366cfSKarsten Keil if (len < 64) { 151960366cfSKarsten Keil if (len > 0) 152960366cfSKarsten Keil printk(KERN_ERR "%s: coefficients have invalid " 153960366cfSKarsten Keil "size. (is=%d < must=%d)\n", 154960366cfSKarsten Keil __func__, len, 64); 155960366cfSKarsten Keil return dsp->dtmf.digits; 156960366cfSKarsten Keil } 157960366cfSKarsten Keil hfccoeff = (s32 *)data; 158960366cfSKarsten Keil for (k = 0; k < NCOEFF; k++) { 159960366cfSKarsten Keil sk2 = (*hfccoeff++)>>4; 160960366cfSKarsten Keil sk = (*hfccoeff++)>>4; 161960366cfSKarsten Keil if (sk > 32767 || sk < -32767 || sk2 > 32767 162960366cfSKarsten Keil || sk2 < -32767) 163960366cfSKarsten Keil printk(KERN_WARNING 164960366cfSKarsten Keil "DTMF-Detection overflow\n"); 165960366cfSKarsten Keil /* compute |X(k)|**2 */ 166960366cfSKarsten Keil result[k] = 167960366cfSKarsten Keil (sk * sk) - 168960366cfSKarsten Keil (((cos2pik[k] * sk) >> 15) * sk2) + 169960366cfSKarsten Keil (sk2 * sk2); 170960366cfSKarsten Keil } 171960366cfSKarsten Keil data += 64; 172960366cfSKarsten Keil len -= 64; 173960366cfSKarsten Keil goto coefficients; 174960366cfSKarsten Keil break; 175960366cfSKarsten Keil } 176960366cfSKarsten Keil dsp->dtmf.size = size; 177960366cfSKarsten Keil 178960366cfSKarsten Keil if (size < DSP_DTMF_NPOINTS) 179960366cfSKarsten Keil return dsp->dtmf.digits; 180960366cfSKarsten Keil 181960366cfSKarsten Keil dsp->dtmf.size = 0; 182960366cfSKarsten Keil 183960366cfSKarsten Keil /* now we have a full buffer of signed long samples - we do goertzel */ 184960366cfSKarsten Keil for (k = 0; k < NCOEFF; k++) { 185960366cfSKarsten Keil sk = 0; 186960366cfSKarsten Keil sk1 = 0; 187960366cfSKarsten Keil sk2 = 0; 188960366cfSKarsten Keil buf = dsp->dtmf.buffer; 189960366cfSKarsten Keil cos2pik_ = cos2pik[k]; 190960366cfSKarsten Keil for (n = 0; n < DSP_DTMF_NPOINTS; n++) { 191960366cfSKarsten Keil sk = ((cos2pik_*sk1)>>15) - sk2 + (*buf++); 192960366cfSKarsten Keil sk2 = sk1; 193960366cfSKarsten Keil sk1 = sk; 194960366cfSKarsten Keil } 195960366cfSKarsten Keil sk >>= 8; 196960366cfSKarsten Keil sk2 >>= 8; 197960366cfSKarsten Keil if (sk > 32767 || sk < -32767 || sk2 > 32767 || sk2 < -32767) 198960366cfSKarsten Keil printk(KERN_WARNING "DTMF-Detection overflow\n"); 199960366cfSKarsten Keil /* compute |X(k)|**2 */ 200960366cfSKarsten Keil result[k] = 201960366cfSKarsten Keil (sk * sk) - 202960366cfSKarsten Keil (((cos2pik[k] * sk) >> 15) * sk2) + 203960366cfSKarsten Keil (sk2 * sk2); 204960366cfSKarsten Keil } 205960366cfSKarsten Keil 206960366cfSKarsten Keil /* our (squared) coefficients have been calculated, we need to process 207960366cfSKarsten Keil * them. 208960366cfSKarsten Keil */ 209960366cfSKarsten Keil coefficients: 210960366cfSKarsten Keil tresh = 0; 211960366cfSKarsten Keil for (i = 0; i < NCOEFF; i++) { 212960366cfSKarsten Keil if (result[i] < 0) 213960366cfSKarsten Keil result[i] = 0; 214960366cfSKarsten Keil if (result[i] > dsp->dtmf.treshold) { 215960366cfSKarsten Keil if (result[i] > tresh) 216960366cfSKarsten Keil tresh = result[i]; 217960366cfSKarsten Keil } 218960366cfSKarsten Keil } 219960366cfSKarsten Keil 220960366cfSKarsten Keil if (tresh == 0) { 221960366cfSKarsten Keil what = 0; 222960366cfSKarsten Keil goto storedigit; 223960366cfSKarsten Keil } 224960366cfSKarsten Keil 225960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_DTMFCOEFF) 226960366cfSKarsten Keil printk(KERN_DEBUG "a %3d %3d %3d %3d %3d %3d %3d %3d" 227960366cfSKarsten Keil " tr:%3d r %3d %3d %3d %3d %3d %3d %3d %3d\n", 228960366cfSKarsten Keil result[0]/10000, result[1]/10000, result[2]/10000, 229960366cfSKarsten Keil result[3]/10000, result[4]/10000, result[5]/10000, 230960366cfSKarsten Keil result[6]/10000, result[7]/10000, tresh/10000, 231960366cfSKarsten Keil result[0]/(tresh/100), result[1]/(tresh/100), 232960366cfSKarsten Keil result[2]/(tresh/100), result[3]/(tresh/100), 233960366cfSKarsten Keil result[4]/(tresh/100), result[5]/(tresh/100), 234960366cfSKarsten Keil result[6]/(tresh/100), result[7]/(tresh/100)); 235960366cfSKarsten Keil 236960366cfSKarsten Keil /* calc digit (lowgroup/highgroup) */ 237960366cfSKarsten Keil lowgroup = -1; 238960366cfSKarsten Keil highgroup = -1; 239960366cfSKarsten Keil treshl = tresh >> 3; /* tones which are not on, must be below 9 dB */ 240960366cfSKarsten Keil tresh = tresh >> 2; /* touchtones must match within 6 dB */ 241960366cfSKarsten Keil for (i = 0; i < NCOEFF; i++) { 242960366cfSKarsten Keil if (result[i] < treshl) 243960366cfSKarsten Keil continue; /* ignore */ 244960366cfSKarsten Keil if (result[i] < tresh) { 245960366cfSKarsten Keil lowgroup = -1; 246960366cfSKarsten Keil highgroup = -1; 247960366cfSKarsten Keil break; /* noise in between */ 248960366cfSKarsten Keil } 249960366cfSKarsten Keil /* good level found. This is allowed only one time per group */ 250960366cfSKarsten Keil if (i < NCOEFF/2) { 251960366cfSKarsten Keil /* lowgroup */ 252960366cfSKarsten Keil if (lowgroup >= 0) { 253960366cfSKarsten Keil /* Bad. Another tone found. */ 254960366cfSKarsten Keil lowgroup = -1; 255960366cfSKarsten Keil break; 256960366cfSKarsten Keil } else 257960366cfSKarsten Keil lowgroup = i; 258960366cfSKarsten Keil } else { 259960366cfSKarsten Keil /* higroup */ 260960366cfSKarsten Keil if (highgroup >= 0) { 261960366cfSKarsten Keil /* Bad. Another tone found. */ 262960366cfSKarsten Keil highgroup = -1; 263960366cfSKarsten Keil break; 264960366cfSKarsten Keil } else 265960366cfSKarsten Keil highgroup = i-(NCOEFF/2); 266960366cfSKarsten Keil } 267960366cfSKarsten Keil } 268960366cfSKarsten Keil 269960366cfSKarsten Keil /* get digit or null */ 270960366cfSKarsten Keil what = 0; 271960366cfSKarsten Keil if (lowgroup >= 0 && highgroup >= 0) 272960366cfSKarsten Keil what = dtmf_matrix[lowgroup][highgroup]; 273960366cfSKarsten Keil 274960366cfSKarsten Keil storedigit: 275960366cfSKarsten Keil if (what && (dsp_debug & DEBUG_DSP_DTMF)) 276960366cfSKarsten Keil printk(KERN_DEBUG "DTMF what: %c\n", what); 277960366cfSKarsten Keil 278960366cfSKarsten Keil if (dsp->dtmf.lastwhat != what) 279960366cfSKarsten Keil dsp->dtmf.count = 0; 280960366cfSKarsten Keil 281960366cfSKarsten Keil /* the tone (or no tone) must remain 3 times without change */ 282960366cfSKarsten Keil if (dsp->dtmf.count == 2) { 283960366cfSKarsten Keil if (dsp->dtmf.lastdigit != what) { 284960366cfSKarsten Keil dsp->dtmf.lastdigit = what; 285960366cfSKarsten Keil if (what) { 286960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_DTMF) 287960366cfSKarsten Keil printk(KERN_DEBUG "DTMF digit: %c\n", 288960366cfSKarsten Keil what); 289960366cfSKarsten Keil if ((strlen(dsp->dtmf.digits)+1) 290960366cfSKarsten Keil < sizeof(dsp->dtmf.digits)) { 291960366cfSKarsten Keil dsp->dtmf.digits[strlen( 292960366cfSKarsten Keil dsp->dtmf.digits)+1] = '\0'; 293960366cfSKarsten Keil dsp->dtmf.digits[strlen( 294960366cfSKarsten Keil dsp->dtmf.digits)] = what; 295960366cfSKarsten Keil } 296960366cfSKarsten Keil } 297960366cfSKarsten Keil } 298960366cfSKarsten Keil } else 299960366cfSKarsten Keil dsp->dtmf.count++; 300960366cfSKarsten Keil 301960366cfSKarsten Keil dsp->dtmf.lastwhat = what; 302960366cfSKarsten Keil 303960366cfSKarsten Keil goto again; 304960366cfSKarsten Keil } 305960366cfSKarsten Keil 306960366cfSKarsten Keil 307