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