configure.ac: add libusb/libusbx support (for xpp)
[dahdi/tools.git] / tonezone.c
1 /*
2  * BSD Telephony Of Mexico "Tormenta" Tone Zone Support 2/22/01
3  * 
4  * Working with the "Tormenta ISA" Card 
5  *
6  * Primary Author: Mark Spencer <markster@digium.com>
7  *
8  */
9
10 /*
11  * See http://www.asterisk.org for more information about
12  * the Asterisk project. Please do not directly contact
13  * any of the maintainers of this project for assistance;
14  * the project provides a web site, mailing lists and IRC
15  * channels for your use.
16  *
17  * This program is free software, distributed under the terms of
18  * the GNU Lesser General Public License Version 2.1 as published
19  * by the Free Software Foundation. See the LICENSE.LGPL file
20  * included with this program for more details.
21  *
22  * In addition, when this program is distributed with Asterisk in
23  * any form that would qualify as a 'combined work' or as a
24  * 'derivative work' (but not mere aggregation), you can redistribute
25  * and/or modify the combination under the terms of the license
26  * provided with that copy of Asterisk, instead of the license
27  * terms granted here.
28  */
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <math.h>
33 #include <sys/ioctl.h>
34 #include <fcntl.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <errno.h>
38
39 #include "dahdi/user.h"
40 #include "tonezone.h"
41 #include "dahdi_tools_version.h"
42
43 #define DEFAULT_DAHDI_DEV "/dev/dahdi/ctl"
44
45 #define MAX_SIZE 16384
46 #define CLIP 32635
47 #define BIAS 0x84
48
49 #if 0
50 # define PRINT_DEBUG(x, ...) printf(x, __VA_ARGS__)
51 #else
52 # define PRINT_DEBUG(x, ...)
53 #endif
54
55 #ifndef ENODATA
56 #define ENODATA EINVAL
57 #endif
58
59 struct tone_zone *tone_zone_find(char *country)
60 {
61         struct tone_zone *z;
62         z = builtin_zones;
63         while(z->zone > -1) {
64                 if (!strcasecmp(country, z->country))
65                         return z;
66                 z++;
67         }
68         return NULL;
69 }
70
71 struct tone_zone *tone_zone_find_by_num(int id)
72 {
73         struct tone_zone *z;
74         z = builtin_zones;
75         while(z->zone > -1) {
76                 if (z->zone == id)
77                         return z;
78                 z++;
79         }
80         return NULL;
81 }
82
83 #define LEVEL -10
84
85 static int build_tone(void *data, size_t size, struct tone_zone_sound *t, int *count)
86 {
87         char *dup, *s;
88         struct dahdi_tone_def *td=NULL;
89         int firstnobang = -1;
90         int freq1, freq2, time;
91         int modulate = 0;
92         float db = 1.0;
93         float gain;
94         int used = 0;
95         dup = strdup(t->data);
96         s = strtok(dup, ",");
97         while(s && strlen(s)) {
98                 /* Handle optional ! which signifies don't start here*/
99                 if (s[0] == '!') {
100                         s++;
101                 } else if (firstnobang < 0) {
102                         PRINT_DEBUG("First no bang: %s\n", s);
103                         firstnobang = *count;
104                 }
105
106                 if (sscanf(s, "%d+%d/%d", &freq1, &freq2, &time) == 3) {
107                         /* f1+f2/time format */
108                         PRINT_DEBUG("f1+f2/time format: %d, %d, %d\n", freq1, freq2, time);
109                 } else if (sscanf(s, "%d*%d/%d", &freq1, &freq2, &time) == 3) {
110                         /* f1*f2/time format */
111                         PRINT_DEBUG("f1+f2/time format: %d, %d, %d\n", freq1, freq2, time);
112                         modulate = 1;
113                 } else if (sscanf(s, "%d+%d", &freq1, &freq2) == 2) {
114                         PRINT_DEBUG("f1+f2 format: %d, %d\n", freq1, freq2);
115                         time = 0;
116                 } else if (sscanf(s, "%d*%d", &freq1, &freq2) == 2) {
117                         PRINT_DEBUG("f1+f2 format: %d, %d\n", freq1, freq2);
118                         modulate = 1;
119                         time = 0;
120                 } else if (sscanf(s, "%d/%d", &freq1, &time) == 2) {
121                         PRINT_DEBUG("f1/time format: %d, %d\n", freq1, time);
122                         freq2 = 0;
123                 } else if (sscanf(s, "%d@/%d", &freq1, &time) == 2) {
124                         /* The "@" character has been added to enable an
125                          * approximately -20db tone generation of any frequency This has been done
126                          * primarily to generate the Australian congestion tone.
127                          * Example: "425/375,0/375,425@/375,0/375" 
128                          */
129                         PRINT_DEBUG("f1 reduced amplitude/time format: %d, %d\n", freq1,time);
130                         db = 0.3;
131                         freq2 = 0;
132                 } else if (sscanf(s, "%d", &freq1) == 1) {
133                         PRINT_DEBUG("f1 format: %d\n", freq1);
134                         firstnobang = *count;
135                         freq2 = 0;
136                         time = 0;
137                 } else {
138                         fprintf(stderr, "tone component '%s' of '%s' is a syntax error\n", s,t->data);
139                         return -1;
140                 }
141
142                 PRINT_DEBUG("Using %d samples for %d and %d\n", time * 8, freq1, freq2);
143
144                 if (size < sizeof(*td)) {
145                         fprintf(stderr, "Not enough space for tones\n");
146                         return -1;
147                 }
148                 td = data;
149
150                 /* Bring it down -8 dbm */
151                 gain = db*(pow(10.0, (LEVEL - 3.14) / 20.0) * 65536.0 / 2.0);
152
153                 td->fac1 = 2.0 * cos(2.0 * M_PI * (freq1 / 8000.0)) * 32768.0;
154                 td->init_v2_1 = sin(-4.0 * M_PI * (freq1 / 8000.0)) * gain;
155                 td->init_v3_1 = sin(-2.0 * M_PI * (freq1 / 8000.0)) * gain;
156                 
157                 td->fac2 = 2.0 * cos(2.0 * M_PI * (freq2 / 8000.0)) * 32768.0;
158                 td->init_v2_2 = sin(-4.0 * M_PI * (freq2 / 8000.0)) * gain;
159                 td->init_v3_2 = sin(-2.0 * M_PI * (freq2 / 8000.0)) * gain;
160
161                 td->modulate = modulate;
162
163                 data += sizeof(*td);
164                 used += sizeof(*td);
165                 size -= sizeof(*td);
166                 td->tone = t->toneid;
167                 if (time) {
168                         /* We should move to the next tone */
169                         td->next = *count + 1;
170                         td->samples = time * 8;
171                 } else {
172                         /* Stay with us */
173                         td->next = *count;
174                         td->samples = 8000;
175                 }
176                 *count += 1;
177                 s = strtok(NULL, ",");
178         }
179         if (td && time) {
180                 /* If we don't end on a solid tone, return */
181                 td->next = firstnobang;
182         }
183         if (firstnobang < 0)
184                 fprintf(stderr, "tone '%s' does not end with a solid tone or silence (all tone components have an exclamation mark)\n", t->data);
185
186         return used;
187 }
188
189 char *tone_zone_tone_name(int id)
190 {
191         static char tmp[80];
192         switch(id) {
193         case DAHDI_TONE_DIALTONE:
194                 return "Dialtone";
195         case DAHDI_TONE_BUSY:
196                 return "Busy";
197         case DAHDI_TONE_RINGTONE:
198                 return "Ringtone";
199         case DAHDI_TONE_CONGESTION:
200                 return "Congestion";
201         case DAHDI_TONE_CALLWAIT:
202                 return "Call Waiting";
203         case DAHDI_TONE_DIALRECALL:
204                 return "Dial Recall";
205         case DAHDI_TONE_RECORDTONE:
206                 return "Record Tone";
207         case DAHDI_TONE_CUST1:
208                 return "Custom 1";
209         case DAHDI_TONE_CUST2:
210                 return "Custom 2";
211         case DAHDI_TONE_INFO:
212                 return "Special Information";
213         case DAHDI_TONE_STUTTER:
214                 return "Stutter Dialtone";
215         default:
216                 snprintf(tmp, sizeof(tmp), "Unknown tone %d", id);
217                 return tmp;
218         }
219 }
220
221 #ifdef TONEZONE_DRIVER
222 static void dump_tone_zone(void *data, int size)
223 {
224         struct dahdi_tone_def_header *z;
225         struct dahdi_tone_def *td;
226         int x;
227         int len = sizeof(*z);
228
229         z = data;
230         data += sizeof(*z);
231         printf("Header: %d tones, %d bytes of data, zone %d (%s)\n", 
232                 z->count, size, z->zone, z->name);
233         for (x = 0; x < z->count; x++) {
234                 td = data;
235                 printf("Tone Fragment %d: tone is %d, next is %d, %d samples\n",
236                         x, td->tone, td->next, td->samples);
237                 data += sizeof(*td);
238                 len += sizeof(*td);
239         }
240         printf("Total measured bytes of data: %d\n", len);
241 }
242 #endif
243
244 /* Tone frequency tables */
245 struct mf_tone {
246         int     tone;
247         float   f1;     /* first freq */
248         float   f2;     /* second freq */
249 };
250  
251 static struct mf_tone dtmf_tones[] = {
252         { DAHDI_TONE_DTMF_0, 941.0, 1336.0 },
253         { DAHDI_TONE_DTMF_1, 697.0, 1209.0 },
254         { DAHDI_TONE_DTMF_2, 697.0, 1336.0 },
255         { DAHDI_TONE_DTMF_3, 697.0, 1477.0 },
256         { DAHDI_TONE_DTMF_4, 770.0, 1209.0 },
257         { DAHDI_TONE_DTMF_5, 770.0, 1336.0 },
258         { DAHDI_TONE_DTMF_6, 770.0, 1477.0 },
259         { DAHDI_TONE_DTMF_7, 852.0, 1209.0 },
260         { DAHDI_TONE_DTMF_8, 852.0, 1336.0 },
261         { DAHDI_TONE_DTMF_9, 852.0, 1477.0 },
262         { DAHDI_TONE_DTMF_s, 941.0, 1209.0 },
263         { DAHDI_TONE_DTMF_p, 941.0, 1477.0 },
264         { DAHDI_TONE_DTMF_A, 697.0, 1633.0 },
265         { DAHDI_TONE_DTMF_B, 770.0, 1633.0 },
266         { DAHDI_TONE_DTMF_C, 852.0, 1633.0 },
267         { DAHDI_TONE_DTMF_D, 941.0, 1633.0 },
268         { 0, 0, 0 }
269 };
270  
271 static struct mf_tone mfr1_tones[] = {
272         { DAHDI_TONE_MFR1_0, 1300.0, 1500.0 },
273         { DAHDI_TONE_MFR1_1, 700.0, 900.0 },
274         { DAHDI_TONE_MFR1_2, 700.0, 1100.0 },
275         { DAHDI_TONE_MFR1_3, 900.0, 1100.0 },
276         { DAHDI_TONE_MFR1_4, 700.0, 1300.0 },
277         { DAHDI_TONE_MFR1_5, 900.0, 1300.0 },
278         { DAHDI_TONE_MFR1_6, 1100.0, 1300.0 },
279         { DAHDI_TONE_MFR1_7, 700.0, 1500.0 },
280         { DAHDI_TONE_MFR1_8, 900.0, 1500.0 },
281         { DAHDI_TONE_MFR1_9, 1100.0, 1500.0 },
282         { DAHDI_TONE_MFR1_KP, 1100.0, 1700.0 }, /* KP */
283         { DAHDI_TONE_MFR1_ST, 1500.0, 1700.0 }, /* ST */
284         { DAHDI_TONE_MFR1_STP, 900.0, 1700.0 }, /* KP' or ST' */
285         { DAHDI_TONE_MFR1_ST2P, 1300.0, 1700.0 },       /* KP'' or ST'' */ 
286         { DAHDI_TONE_MFR1_ST3P, 700.0, 1700.0 },        /* KP''' or ST''' */
287         { 0, 0, 0 }
288 };
289
290 static struct mf_tone mfr2_fwd_tones[] = {
291         { DAHDI_TONE_MFR2_FWD_1, 1380.0, 1500.0 },
292         { DAHDI_TONE_MFR2_FWD_2, 1380.0, 1620.0 },
293         { DAHDI_TONE_MFR2_FWD_3, 1500.0, 1620.0 },
294         { DAHDI_TONE_MFR2_FWD_4, 1380.0, 1740.0 },
295         { DAHDI_TONE_MFR2_FWD_5, 1500.0, 1740.0 },
296         { DAHDI_TONE_MFR2_FWD_6, 1620.0, 1740.0 },
297         { DAHDI_TONE_MFR2_FWD_7, 1380.0, 1860.0 },
298         { DAHDI_TONE_MFR2_FWD_8, 1500.0, 1860.0 },
299         { DAHDI_TONE_MFR2_FWD_9, 1620.0, 1860.0 },
300         { DAHDI_TONE_MFR2_FWD_10, 1740.0, 1860.0 },
301         { DAHDI_TONE_MFR2_FWD_11, 1380.0, 1980.0 },
302         { DAHDI_TONE_MFR2_FWD_12, 1500.0, 1980.0 },
303         { DAHDI_TONE_MFR2_FWD_13, 1620.0, 1980.0 },
304         { DAHDI_TONE_MFR2_FWD_14, 1740.0, 1980.0 },
305         { DAHDI_TONE_MFR2_FWD_15, 1860.0, 1980.0 },
306         { 0, 0, 0 }
307 };
308
309 static struct mf_tone mfr2_rev_tones[] = {
310         { DAHDI_TONE_MFR2_REV_1, 1020.0, 1140.0 },
311         { DAHDI_TONE_MFR2_REV_2, 900.0, 1140.0 },
312         { DAHDI_TONE_MFR2_REV_3, 900.0, 1020.0 },
313         { DAHDI_TONE_MFR2_REV_4, 780.0, 1140.0 },
314         { DAHDI_TONE_MFR2_REV_5, 780.0, 1020.0 },
315         { DAHDI_TONE_MFR2_REV_6, 780.0, 900.0 },
316         { DAHDI_TONE_MFR2_REV_7, 660.0, 1140.0 },
317         { DAHDI_TONE_MFR2_REV_8, 660.0, 1020.0 },
318         { DAHDI_TONE_MFR2_REV_9, 660.0, 900.0 },
319         { DAHDI_TONE_MFR2_REV_10, 660.0, 780.0 },
320         { DAHDI_TONE_MFR2_REV_11, 540.0, 1140.0 },
321         { DAHDI_TONE_MFR2_REV_12, 540.0, 1020.0 },
322         { DAHDI_TONE_MFR2_REV_13, 540.0, 900.0 },
323         { DAHDI_TONE_MFR2_REV_14, 540.0, 780.0 },
324         { DAHDI_TONE_MFR2_REV_15, 540.0, 660.0 },
325         { 0, 0, 0 }
326 };
327
328 static int build_mf_tones(void *data, size_t size, int *count, struct mf_tone *tone, int low_tone_level, int high_tone_level)
329 {
330         struct dahdi_tone_def *td;
331         float gain;
332         int used = 0;
333
334         while (tone->tone) {
335                 if (size < sizeof(*td)) {
336                         fprintf(stderr, "Not enough space for samples\n");
337                         return -1;
338                 }
339                 td = data;
340                 data += sizeof(*td);
341                 used += sizeof(*td);
342                 size -= sizeof(*td);
343                 td->tone = tone->tone;
344                 *count += 1;
345
346                 /* Bring it down 6 dBm */
347                 gain = pow(10.0, (low_tone_level - 3.14) / 20.0) * 65536.0 / 2.0;
348                 td->fac1 = 2.0 * cos(2.0 * M_PI * (tone->f1 / 8000.0)) * 32768.0;
349                 td->init_v2_1 = sin(-4.0 * M_PI * (tone->f1 / 8000.0)) * gain;
350                 td->init_v3_1 = sin(-2.0 * M_PI * (tone->f1 / 8000.0)) * gain;
351                 
352                 gain = pow(10.0, (high_tone_level - 3.14) / 20.0) * 65536.0 / 2.0;
353                 td->fac2 = 2.0 * cos(2.0 * M_PI * (tone->f2 / 8000.0)) * 32768.0;
354                 td->init_v2_2 = sin(-4.0 * M_PI * (tone->f2 / 8000.0)) * gain;
355                 td->init_v3_2 = sin(-2.0 * M_PI * (tone->f2 / 8000.0)) * gain;
356
357                 tone++;
358         }
359
360         return used;
361 }
362
363 int tone_zone_register_zone(int fd, struct tone_zone *z)
364 {
365         char buf[MAX_SIZE];
366         int res;
367         int count = 0;
368         int x;
369         size_t space = MAX_SIZE;
370         void *ptr = buf;
371         int iopenedit = 1;
372         struct dahdi_tone_def_header *h;
373
374         memset(buf, 0, sizeof(buf));
375
376         h = ptr;
377         ptr += sizeof(*h);
378         space -= sizeof(*h);
379         h->zone = z->zone;
380
381         dahdi_copy_string(h->name, z->description, sizeof(h->name));
382
383         for (x = 0; x < DAHDI_MAX_CADENCE; x++) 
384                 h->ringcadence[x] = z->ringcadence[x];
385
386         for (x = 0; x < DAHDI_TONE_MAX; x++) {
387                 if (!strlen(z->tones[x].data))
388                         continue;
389
390                 PRINT_DEBUG("Tone: %d, string: %s\n", z->tones[x].toneid, z->tones[x].data);
391
392                 if ((res = build_tone(ptr, space, &z->tones[x], &count)) < 0) {
393                         fprintf(stderr, "Tone %d not built.\n", x);
394                         return -1;
395                 }
396                 ptr += res;
397                 space -= res;
398         }
399
400         if ((res = build_mf_tones(ptr, space, &count, dtmf_tones, z->dtmf_low_level, z->dtmf_high_level)) < 0) {
401                 fprintf(stderr, "Could not build DTMF tones.\n");
402                 return -1;
403         }
404         ptr += res;
405         space -= res;
406
407         if ((res = build_mf_tones(ptr, space, &count, mfr1_tones, z->mfr1_level, z->mfr1_level)) < 0) {
408                 fprintf(stderr, "Could not build MFR1 tones.\n");
409                 return -1;
410         }
411         ptr += res;
412         space -= res;
413
414         if ((res = build_mf_tones(ptr, space, &count, mfr2_fwd_tones, z->mfr2_level, z->mfr2_level)) < 0) {
415                 fprintf(stderr, "Could not build MFR2 FWD tones.\n");
416                 return -1;
417         }
418         ptr += res;
419         space -= res;
420
421         if ((res = build_mf_tones(ptr, space, &count, mfr2_rev_tones, z->mfr2_level, z->mfr2_level)) < 0) {
422                 fprintf(stderr, "Could not build MFR2 REV tones.\n");
423                 return -1;
424         }
425         ptr += res;
426         space -= res;
427
428         h->count = count;
429
430         if (fd < 0) {
431                 if ((fd = open(DEFAULT_DAHDI_DEV, O_RDWR)) < 0) {
432                         fprintf(stderr, "Unable to open %s and fd not provided\n", DEFAULT_DAHDI_DEV);
433                         return -1;
434                 }
435                 iopenedit = 1;
436         }
437
438         x = z->zone;
439         if ((res = ioctl(fd, DAHDI_FREEZONE, &x))) {
440                 if (errno != EBUSY)
441                         fprintf(stderr, "ioctl(DAHDI_FREEZONE) failed: %s\n", strerror(errno));
442                 return res;
443         }
444
445 #if defined(TONEZONE_DRIVER)
446         dump_tone_zone(h, MAX_SIZE - space);
447 #endif
448
449 #if defined(__FreeBSD__)
450         if ((res = ioctl(fd, DAHDI_LOADZONE, &h))) {
451 #else
452         if ((res = ioctl(fd, DAHDI_LOADZONE, h))) {
453 #endif
454                 fprintf(stderr, "ioctl(DAHDI_LOADZONE) failed: %s\n", strerror(errno));
455                 return res;
456         }
457
458         if (iopenedit)
459                 close(fd);
460
461         return res;
462 }
463
464 int tone_zone_register(int fd, char *country)
465 {
466         struct tone_zone *z;
467         z = tone_zone_find(country);
468         if (z) {
469                 return tone_zone_register_zone(-1, z);
470         } else {
471                 return -1;
472         }
473 }
474
475 int tone_zone_set_zone(int fd, char *country)
476 {
477         int res=-1;
478         struct tone_zone *z;
479         if (fd > -1) {
480                 z = tone_zone_find(country);
481                 if (z)
482                         res = ioctl(fd, DAHDI_SETTONEZONE, &z->zone);
483                 if ((res < 0) && (errno == ENODATA)) {
484                         tone_zone_register_zone(fd, z);
485                         res = ioctl(fd, DAHDI_SETTONEZONE, &z->zone);
486                 }
487         }
488         return res;
489 }
490
491 int tone_zone_get_zone(int fd)
492 {
493         int x=-1;
494         if (fd > -1) {
495                 ioctl(fd, DAHDI_GETTONEZONE, &x);
496                 return x;
497         }
498         return -1;
499 }
500
501 int tone_zone_play_tone(int fd, int tone)
502 {
503         struct tone_zone *z;
504         int res = -1;
505         int zone;
506
507 #if 0
508         fprintf(stderr, "Playing tone %d (%s) on %d\n", tone, tone_zone_tone_name(tone), fd);
509 #endif
510         if (fd > -1) {
511                 res = ioctl(fd, DAHDI_SENDTONE, &tone);
512                 if ((res < 0) && (errno == ENODATA)) {
513                         ioctl(fd, DAHDI_GETTONEZONE, &zone);
514                         z = tone_zone_find_by_num(zone);
515                         if (z) {
516                                 res = tone_zone_register_zone(fd, z);
517                                 /* Recall the zone */
518                                 ioctl(fd, DAHDI_SETTONEZONE, &zone);
519                                 if (res < 0) {
520                                         fprintf(stderr, "Failed to register zone '%s': %s\n", z->description, strerror(errno));
521                                 } else {
522                                         res = ioctl(fd, DAHDI_SENDTONE, &tone);
523                                 }
524                         } else
525                                 fprintf(stderr, "Don't know anything about zone %d\n", zone);
526                 }
527         }
528         return res;
529 }