Import DAHDI-Tools r9159
[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 gain;
93         int used = 0;
94         dup = strdup(t->data);
95         s = strtok(dup, ",");
96         while(s && strlen(s)) {
97                 /* Handle optional ! which signifies don't start here*/
98                 if (s[0] == '!') 
99                         s++;
100                 else if (firstnobang < 0) {
101                         PRINT_DEBUG("First no bang: %s\n", s);
102                         firstnobang = *count;
103                 }
104                 if (sscanf(s, "%d+%d/%d", &freq1, &freq2, &time) == 3) {
105                         /* f1+f2/time format */
106                         PRINT_DEBUG("f1+f2/time format: %d, %d, %d\n", freq1, freq2, time);
107                 } else if (sscanf(s, "%d*%d/%d", &freq1, &freq2, &time) == 3) {
108                         /* f1*f2/time format */
109                         PRINT_DEBUG("f1+f2/time format: %d, %d, %d\n", freq1, freq2, time);
110                         modulate = 1;
111                 } else if (sscanf(s, "%d+%d", &freq1, &freq2) == 2) {
112                         PRINT_DEBUG("f1+f2 format: %d, %d\n", freq1, freq2);
113                         time = 0;
114                 } else if (sscanf(s, "%d*%d", &freq1, &freq2) == 2) {
115                         PRINT_DEBUG("f1+f2 format: %d, %d\n", freq1, freq2);
116                         modulate = 1;
117                         time = 0;
118                 } else if (sscanf(s, "%d/%d", &freq1, &time) == 2) {
119                         PRINT_DEBUG("f1/time format: %d, %d\n", freq1, time);
120                         freq2 = 0;
121                 } else if (sscanf(s, "%d", &freq1) == 1) {
122                         PRINT_DEBUG("f1 format: %d\n", freq1);
123                         firstnobang = *count;
124                         freq2 = 0;
125                         time = 0;
126                 } else {
127                         fprintf(stderr, "tone component '%s' of '%s' is a syntax error\n", s,t->data);
128                         return -1;
129                 }
130
131                 PRINT_DEBUG("Using %d samples for %d and %d\n", time * 8, freq1, freq2);
132
133                 if (size < sizeof(*td)) {
134                         fprintf(stderr, "Not enough space for tones\n");
135                         return -1;
136                 }
137                 td = data;
138
139                 /* Bring it down -8 dbm */
140                 gain = pow(10.0, (LEVEL - 3.14) / 20.0) * 65536.0 / 2.0;
141
142                 td->fac1 = 2.0 * cos(2.0 * M_PI * (freq1 / 8000.0)) * 32768.0;
143                 td->init_v2_1 = sin(-4.0 * M_PI * (freq1 / 8000.0)) * gain;
144                 td->init_v3_1 = sin(-2.0 * M_PI * (freq1 / 8000.0)) * gain;
145                 
146                 td->fac2 = 2.0 * cos(2.0 * M_PI * (freq2 / 8000.0)) * 32768.0;
147                 td->init_v2_2 = sin(-4.0 * M_PI * (freq2 / 8000.0)) * gain;
148                 td->init_v3_2 = sin(-2.0 * M_PI * (freq2 / 8000.0)) * gain;
149
150                 td->modulate = modulate;
151
152                 data += sizeof(*td);
153                 used += sizeof(*td);
154                 size -= sizeof(*td);
155                 td->tone = t->toneid;
156                 if (time) {
157                         /* We should move to the next tone */
158                         td->next = *count + 1;
159                         td->samples = time * 8;
160                 } else {
161                         /* Stay with us */
162                         td->next = *count;
163                         td->samples = 8000;
164                 }
165                 *count += 1;
166                 s = strtok(NULL, ",");
167         }
168         if (td && time) {
169                 /* If we don't end on a solid tone, return */
170                 td->next = firstnobang;
171         }
172         if (firstnobang < 0)
173                 fprintf(stderr, "tone '%s' does not end with a solid tone or silence (all tone components have an exclamation mark)\n", t->data);
174
175         return used;
176 }
177
178 char *tone_zone_tone_name(int id)
179 {
180         static char tmp[80];
181         switch(id) {
182         case DAHDI_TONE_DIALTONE:
183                 return "Dialtone";
184         case DAHDI_TONE_BUSY:
185                 return "Busy";
186         case DAHDI_TONE_RINGTONE:
187                 return "Ringtone";
188         case DAHDI_TONE_CONGESTION:
189                 return "Congestion";
190         case DAHDI_TONE_CALLWAIT:
191                 return "Call Waiting";
192         case DAHDI_TONE_DIALRECALL:
193                 return "Dial Recall";
194         case DAHDI_TONE_RECORDTONE:
195                 return "Record Tone";
196         case DAHDI_TONE_CUST1:
197                 return "Custom 1";
198         case DAHDI_TONE_CUST2:
199                 return "Custom 2";
200         case DAHDI_TONE_INFO:
201                 return "Special Information";
202         case DAHDI_TONE_STUTTER:
203                 return "Stutter Dialtone";
204         default:
205                 snprintf(tmp, sizeof(tmp), "Unknown tone %d", id);
206                 return tmp;
207         }
208 }
209
210 #ifdef TONEZONE_DRIVER
211 static void dump_tone_zone(void *data, int size)
212 {
213         struct dahdi_tone_def_header *z;
214         struct dahdi_tone_def *td;
215         int x;
216         int len = sizeof(*z);
217
218         z = data;
219         data += sizeof(*z);
220         printf("Header: %d tones, %d bytes of data, zone %d (%s)\n", 
221                 z->count, size, z->zone, z->name);
222         for (x = 0; x < z->count; x++) {
223                 td = data;
224                 printf("Tone Fragment %d: tone is %d, next is %d, %d samples\n",
225                         x, td->tone, td->next, td->samples);
226                 data += sizeof(*td);
227                 len += sizeof(*td);
228         }
229         printf("Total measured bytes of data: %d\n", len);
230 }
231 #endif
232
233 /* Tone frequency tables */
234 struct mf_tone {
235         int     tone;
236         float   f1;     /* first freq */
237         float   f2;     /* second freq */
238 };
239  
240 static struct mf_tone dtmf_tones[] = {
241         { DAHDI_TONE_DTMF_0, 941.0, 1336.0 },
242         { DAHDI_TONE_DTMF_1, 697.0, 1209.0 },
243         { DAHDI_TONE_DTMF_2, 697.0, 1336.0 },
244         { DAHDI_TONE_DTMF_3, 697.0, 1477.0 },
245         { DAHDI_TONE_DTMF_4, 770.0, 1209.0 },
246         { DAHDI_TONE_DTMF_5, 770.0, 1336.0 },
247         { DAHDI_TONE_DTMF_6, 770.0, 1477.0 },
248         { DAHDI_TONE_DTMF_7, 852.0, 1209.0 },
249         { DAHDI_TONE_DTMF_8, 852.0, 1336.0 },
250         { DAHDI_TONE_DTMF_9, 852.0, 1477.0 },
251         { DAHDI_TONE_DTMF_s, 941.0, 1209.0 },
252         { DAHDI_TONE_DTMF_p, 941.0, 1477.0 },
253         { DAHDI_TONE_DTMF_A, 697.0, 1633.0 },
254         { DAHDI_TONE_DTMF_B, 770.0, 1633.0 },
255         { DAHDI_TONE_DTMF_C, 852.0, 1633.0 },
256         { DAHDI_TONE_DTMF_D, 941.0, 1633.0 },
257         { 0, 0, 0 }
258 };
259  
260 static struct mf_tone mfr1_tones[] = {
261         { DAHDI_TONE_MFR1_0, 1300.0, 1500.0 },
262         { DAHDI_TONE_MFR1_1, 700.0, 900.0 },
263         { DAHDI_TONE_MFR1_2, 700.0, 1100.0 },
264         { DAHDI_TONE_MFR1_3, 900.0, 1100.0 },
265         { DAHDI_TONE_MFR1_4, 700.0, 1300.0 },
266         { DAHDI_TONE_MFR1_5, 900.0, 1300.0 },
267         { DAHDI_TONE_MFR1_6, 1100.0, 1300.0 },
268         { DAHDI_TONE_MFR1_7, 700.0, 1500.0 },
269         { DAHDI_TONE_MFR1_8, 900.0, 1500.0 },
270         { DAHDI_TONE_MFR1_9, 1100.0, 1500.0 },
271         { DAHDI_TONE_MFR1_KP, 1100.0, 1700.0 }, /* KP */
272         { DAHDI_TONE_MFR1_ST, 1500.0, 1700.0 }, /* ST */
273         { DAHDI_TONE_MFR1_STP, 900.0, 1700.0 }, /* KP' or ST' */
274         { DAHDI_TONE_MFR1_ST2P, 1300.0, 1700.0 },       /* KP'' or ST'' */ 
275         { DAHDI_TONE_MFR1_ST3P, 700.0, 1700.0 },        /* KP''' or ST''' */
276         { 0, 0, 0 }
277 };
278
279 static struct mf_tone mfr2_fwd_tones[] = {
280         { DAHDI_TONE_MFR2_FWD_1, 1380.0, 1500.0 },
281         { DAHDI_TONE_MFR2_FWD_2, 1380.0, 1620.0 },
282         { DAHDI_TONE_MFR2_FWD_3, 1500.0, 1620.0 },
283         { DAHDI_TONE_MFR2_FWD_4, 1380.0, 1740.0 },
284         { DAHDI_TONE_MFR2_FWD_5, 1500.0, 1740.0 },
285         { DAHDI_TONE_MFR2_FWD_6, 1620.0, 1740.0 },
286         { DAHDI_TONE_MFR2_FWD_7, 1380.0, 1860.0 },
287         { DAHDI_TONE_MFR2_FWD_8, 1500.0, 1860.0 },
288         { DAHDI_TONE_MFR2_FWD_9, 1620.0, 1860.0 },
289         { DAHDI_TONE_MFR2_FWD_10, 1740.0, 1860.0 },
290         { DAHDI_TONE_MFR2_FWD_11, 1380.0, 1980.0 },
291         { DAHDI_TONE_MFR2_FWD_12, 1500.0, 1980.0 },
292         { DAHDI_TONE_MFR2_FWD_13, 1620.0, 1980.0 },
293         { DAHDI_TONE_MFR2_FWD_14, 1740.0, 1980.0 },
294         { DAHDI_TONE_MFR2_FWD_15, 1860.0, 1980.0 },
295         { 0, 0, 0 }
296 };
297
298 static struct mf_tone mfr2_rev_tones[] = {
299         { DAHDI_TONE_MFR2_REV_1, 1020.0, 1140.0 },
300         { DAHDI_TONE_MFR2_REV_2, 900.0, 1140.0 },
301         { DAHDI_TONE_MFR2_REV_3, 900.0, 1020.0 },
302         { DAHDI_TONE_MFR2_REV_4, 780.0, 1140.0 },
303         { DAHDI_TONE_MFR2_REV_5, 780.0, 1020.0 },
304         { DAHDI_TONE_MFR2_REV_6, 780.0, 900.0 },
305         { DAHDI_TONE_MFR2_REV_7, 660.0, 1140.0 },
306         { DAHDI_TONE_MFR2_REV_8, 660.0, 1020.0 },
307         { DAHDI_TONE_MFR2_REV_9, 660.0, 900.0 },
308         { DAHDI_TONE_MFR2_REV_10, 660.0, 780.0 },
309         { DAHDI_TONE_MFR2_REV_11, 540.0, 1140.0 },
310         { DAHDI_TONE_MFR2_REV_12, 540.0, 1020.0 },
311         { DAHDI_TONE_MFR2_REV_13, 540.0, 900.0 },
312         { DAHDI_TONE_MFR2_REV_14, 540.0, 780.0 },
313         { DAHDI_TONE_MFR2_REV_15, 540.0, 660.0 },
314         { 0, 0, 0 }
315 };
316
317 static int build_mf_tones(void *data, size_t size, int *count, struct mf_tone *tone, int low_tone_level, int high_tone_level)
318 {
319         struct dahdi_tone_def *td;
320         float gain;
321         int used = 0;
322
323         while (tone->tone) {
324                 if (size < sizeof(*td)) {
325                         fprintf(stderr, "Not enough space for samples\n");
326                         return -1;
327                 }
328                 td = data;
329                 data += sizeof(*td);
330                 used += sizeof(*td);
331                 size -= sizeof(*td);
332                 td->tone = tone->tone;
333                 *count += 1;
334
335                 /* Bring it down 6 dBm */
336                 gain = pow(10.0, (low_tone_level - 3.14) / 20.0) * 65536.0 / 2.0;
337                 td->fac1 = 2.0 * cos(2.0 * M_PI * (tone->f1 / 8000.0)) * 32768.0;
338                 td->init_v2_1 = sin(-4.0 * M_PI * (tone->f1 / 8000.0)) * gain;
339                 td->init_v3_1 = sin(-2.0 * M_PI * (tone->f1 / 8000.0)) * gain;
340                 
341                 gain = pow(10.0, (high_tone_level - 3.14) / 20.0) * 65536.0 / 2.0;
342                 td->fac2 = 2.0 * cos(2.0 * M_PI * (tone->f2 / 8000.0)) * 32768.0;
343                 td->init_v2_2 = sin(-4.0 * M_PI * (tone->f2 / 8000.0)) * gain;
344                 td->init_v3_2 = sin(-2.0 * M_PI * (tone->f2 / 8000.0)) * gain;
345
346                 tone++;
347         }
348
349         return used;
350 }
351
352 int tone_zone_register_zone(int fd, struct tone_zone *z)
353 {
354         char buf[MAX_SIZE];
355         int res;
356         int count = 0;
357         int x;
358         size_t space = MAX_SIZE;
359         void *ptr = buf;
360         int iopenedit = 1;
361         struct dahdi_tone_def_header *h;
362
363         memset(buf, 0, sizeof(buf));
364
365         h = ptr;
366         ptr += sizeof(*h);
367         space -= sizeof(*h);
368         h->zone = z->zone;
369
370         dahdi_copy_string(h->name, z->description, sizeof(h->name));
371
372         for (x = 0; x < DAHDI_MAX_CADENCE; x++) 
373                 h->ringcadence[x] = z->ringcadence[x];
374
375         for (x = 0; x < DAHDI_TONE_MAX; x++) {
376                 if (!strlen(z->tones[x].data))
377                         continue;
378
379                 PRINT_DEBUG("Tone: %d, string: %s\n", z->tones[x].toneid, z->tones[x].data);
380
381                 if ((res = build_tone(ptr, space, &z->tones[x], &count)) < 0) {
382                         fprintf(stderr, "Tone %d not built.\n", x);
383                         return -1;
384                 }
385                 ptr += res;
386                 space -= res;
387         }
388
389         if ((res = build_mf_tones(ptr, space, &count, dtmf_tones, z->dtmf_low_level, z->dtmf_high_level)) < 0) {
390                 fprintf(stderr, "Could not build DTMF tones.\n");
391                 return -1;
392         }
393         ptr += res;
394         space -= res;
395
396         if ((res = build_mf_tones(ptr, space, &count, mfr1_tones, z->mfr1_level, z->mfr1_level)) < 0) {
397                 fprintf(stderr, "Could not build MFR1 tones.\n");
398                 return -1;
399         }
400         ptr += res;
401         space -= res;
402
403         if ((res = build_mf_tones(ptr, space, &count, mfr2_fwd_tones, z->mfr2_level, z->mfr2_level)) < 0) {
404                 fprintf(stderr, "Could not build MFR2 FWD tones.\n");
405                 return -1;
406         }
407         ptr += res;
408         space -= res;
409
410         if ((res = build_mf_tones(ptr, space, &count, mfr2_rev_tones, z->mfr2_level, z->mfr2_level)) < 0) {
411                 fprintf(stderr, "Could not build MFR2 REV tones.\n");
412                 return -1;
413         }
414         ptr += res;
415         space -= res;
416
417         h->count = count;
418
419         if (fd < 0) {
420                 if ((fd = open(DEFAULT_DAHDI_DEV, O_RDWR)) < 0) {
421                         fprintf(stderr, "Unable to open %s and fd not provided\n", DEFAULT_DAHDI_DEV);
422                         return -1;
423                 }
424                 iopenedit = 1;
425         }
426
427         x = z->zone;
428         if ((res = ioctl(fd, DAHDI_FREEZONE, &x))) {
429                 if (errno != EBUSY)
430                         fprintf(stderr, "ioctl(DAHDI_FREEZONE) failed: %s\n", strerror(errno));
431                 return res;
432         }
433
434 #if defined(TONEZONE_DRIVER)
435         dump_tone_zone(h, MAX_SIZE - space);
436 #endif
437
438 #if defined(__FreeBSD__)
439         if ((res = ioctl(fd, DAHDI_LOADZONE, &h))) {
440 #else
441         if ((res = ioctl(fd, DAHDI_LOADZONE, h))) {
442 #endif
443                 fprintf(stderr, "ioctl(DAHDI_LOADZONE) failed: %s\n", strerror(errno));
444                 return res;
445         }
446
447         if (iopenedit)
448                 close(fd);
449
450         return res;
451 }
452
453 int tone_zone_register(int fd, char *country)
454 {
455         struct tone_zone *z;
456         z = tone_zone_find(country);
457         if (z) {
458                 return tone_zone_register_zone(-1, z);
459         } else {
460                 return -1;
461         }
462 }
463
464 int tone_zone_set_zone(int fd, char *country)
465 {
466         int res=-1;
467         struct tone_zone *z;
468         if (fd > -1) {
469                 z = tone_zone_find(country);
470                 if (z)
471                         res = ioctl(fd, DAHDI_SETTONEZONE, &z->zone);
472                 if ((res < 0) && (errno == ENODATA)) {
473                         tone_zone_register_zone(fd, z);
474                         res = ioctl(fd, DAHDI_SETTONEZONE, &z->zone);
475                 }
476         }
477         return res;
478 }
479
480 int tone_zone_get_zone(int fd)
481 {
482         int x=-1;
483         if (fd > -1) {
484                 ioctl(fd, DAHDI_GETTONEZONE, &x);
485                 return x;
486         }
487         return -1;
488 }
489
490 int tone_zone_play_tone(int fd, int tone)
491 {
492         struct tone_zone *z;
493         int res = -1;
494         int zone;
495
496 #if 0
497         fprintf(stderr, "Playing tone %d (%s) on %d\n", tone, tone_zone_tone_name(tone), fd);
498 #endif
499         if (fd > -1) {
500                 res = ioctl(fd, DAHDI_SENDTONE, &tone);
501                 if ((res < 0) && (errno == ENODATA)) {
502                         ioctl(fd, DAHDI_GETTONEZONE, &zone);
503                         z = tone_zone_find_by_num(zone);
504                         if (z) {
505                                 res = tone_zone_register_zone(fd, z);
506                                 /* Recall the zone */
507                                 ioctl(fd, DAHDI_SETTONEZONE, &zone);
508                                 if (res < 0) {
509                                         fprintf(stderr, "Failed to register zone '%s': %s\n", z->description, strerror(errno));
510                                 } else {
511                                         res = ioctl(fd, DAHDI_SENDTONE, &tone);
512                                 }
513                         } else
514                                 fprintf(stderr, "Don't know anything about zone %d\n", zone);
515                 }
516         }
517         return res;
518 }