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 */
dsp_dtmf_goertzel_init(struct dsp * dsp)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 */
dsp_dtmf_hardware(struct dsp * dsp)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.
10925985edcSLucas 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
dsp_dtmf_goertzel_decode(struct dsp * dsp,u8 * data,int len,int fmt)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
225*efef50a5SKarsten Keil if (dsp_debug & DEBUG_DSP_DTMFCOEFF) {
226*efef50a5SKarsten Keil s32 tresh_100 = tresh/100;
227*efef50a5SKarsten Keil
228*efef50a5SKarsten Keil if (tresh_100 == 0) {
229*efef50a5SKarsten Keil tresh_100 = 1;
230*efef50a5SKarsten Keil printk(KERN_DEBUG
231*efef50a5SKarsten Keil "tresh(%d) too small set tresh/100 to 1\n",
232*efef50a5SKarsten Keil tresh);
233*efef50a5SKarsten Keil }
234960366cfSKarsten Keil printk(KERN_DEBUG "a %3d %3d %3d %3d %3d %3d %3d %3d"
235960366cfSKarsten Keil " tr:%3d r %3d %3d %3d %3d %3d %3d %3d %3d\n",
236960366cfSKarsten Keil result[0] / 10000, result[1] / 10000, result[2] / 10000,
237960366cfSKarsten Keil result[3] / 10000, result[4] / 10000, result[5] / 10000,
238960366cfSKarsten Keil result[6] / 10000, result[7] / 10000, tresh / 10000,
239*efef50a5SKarsten Keil result[0] / (tresh_100), result[1] / (tresh_100),
240*efef50a5SKarsten Keil result[2] / (tresh_100), result[3] / (tresh_100),
241*efef50a5SKarsten Keil result[4] / (tresh_100), result[5] / (tresh_100),
242*efef50a5SKarsten Keil result[6] / (tresh_100), result[7] / (tresh_100));
243*efef50a5SKarsten Keil }
244960366cfSKarsten Keil
245960366cfSKarsten Keil /* calc digit (lowgroup/highgroup) */
246960366cfSKarsten Keil lowgroup = -1;
247960366cfSKarsten Keil highgroup = -1;
248960366cfSKarsten Keil treshl = tresh >> 3; /* tones which are not on, must be below 9 dB */
249960366cfSKarsten Keil tresh = tresh >> 2; /* touchtones must match within 6 dB */
250960366cfSKarsten Keil for (i = 0; i < NCOEFF; i++) {
251960366cfSKarsten Keil if (result[i] < treshl)
252960366cfSKarsten Keil continue; /* ignore */
253960366cfSKarsten Keil if (result[i] < tresh) {
254960366cfSKarsten Keil lowgroup = -1;
255960366cfSKarsten Keil highgroup = -1;
256960366cfSKarsten Keil break; /* noise in between */
257960366cfSKarsten Keil }
258960366cfSKarsten Keil /* good level found. This is allowed only one time per group */
259960366cfSKarsten Keil if (i < NCOEFF / 2) {
260960366cfSKarsten Keil /* lowgroup */
261960366cfSKarsten Keil if (lowgroup >= 0) {
262960366cfSKarsten Keil /* Bad. Another tone found. */
263960366cfSKarsten Keil lowgroup = -1;
264960366cfSKarsten Keil break;
265960366cfSKarsten Keil } else
266960366cfSKarsten Keil lowgroup = i;
267960366cfSKarsten Keil } else {
268960366cfSKarsten Keil /* higroup */
269960366cfSKarsten Keil if (highgroup >= 0) {
270960366cfSKarsten Keil /* Bad. Another tone found. */
271960366cfSKarsten Keil highgroup = -1;
272960366cfSKarsten Keil break;
273960366cfSKarsten Keil } else
274960366cfSKarsten Keil highgroup = i - (NCOEFF / 2);
275960366cfSKarsten Keil }
276960366cfSKarsten Keil }
277960366cfSKarsten Keil
278960366cfSKarsten Keil /* get digit or null */
279960366cfSKarsten Keil what = 0;
280960366cfSKarsten Keil if (lowgroup >= 0 && highgroup >= 0)
281960366cfSKarsten Keil what = dtmf_matrix[lowgroup][highgroup];
282960366cfSKarsten Keil
283960366cfSKarsten Keil storedigit:
284960366cfSKarsten Keil if (what && (dsp_debug & DEBUG_DSP_DTMF))
285960366cfSKarsten Keil printk(KERN_DEBUG "DTMF what: %c\n", what);
286960366cfSKarsten Keil
287960366cfSKarsten Keil if (dsp->dtmf.lastwhat != what)
288960366cfSKarsten Keil dsp->dtmf.count = 0;
289960366cfSKarsten Keil
290960366cfSKarsten Keil /* the tone (or no tone) must remain 3 times without change */
291960366cfSKarsten Keil if (dsp->dtmf.count == 2) {
292960366cfSKarsten Keil if (dsp->dtmf.lastdigit != what) {
293960366cfSKarsten Keil dsp->dtmf.lastdigit = what;
294960366cfSKarsten Keil if (what) {
295960366cfSKarsten Keil if (dsp_debug & DEBUG_DSP_DTMF)
296960366cfSKarsten Keil printk(KERN_DEBUG "DTMF digit: %c\n",
297960366cfSKarsten Keil what);
298960366cfSKarsten Keil if ((strlen(dsp->dtmf.digits) + 1)
299960366cfSKarsten Keil < sizeof(dsp->dtmf.digits)) {
300960366cfSKarsten Keil dsp->dtmf.digits[strlen(
301960366cfSKarsten Keil dsp->dtmf.digits) + 1] = '\0';
302960366cfSKarsten Keil dsp->dtmf.digits[strlen(
303960366cfSKarsten Keil dsp->dtmf.digits)] = what;
304960366cfSKarsten Keil }
305960366cfSKarsten Keil }
306960366cfSKarsten Keil }
307960366cfSKarsten Keil } else
308960366cfSKarsten Keil dsp->dtmf.count++;
309960366cfSKarsten Keil
310960366cfSKarsten Keil dsp->dtmf.lastwhat = what;
311960366cfSKarsten Keil
312960366cfSKarsten Keil goto again;
313960366cfSKarsten Keil }
314