From a2bbaa084edb6a669880368fc63c1cf62b5c4f42 Mon Sep 17 00:00:00 2001 From: markster Date: Fri, 8 Jun 2001 16:13:48 +0000 Subject: Version 0.1.0 from FTP git-svn-id: http://svn.digium.com/svn/zaptel/trunk@6 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- tonezone.c | 412 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 412 insertions(+) create mode 100755 tonezone.c (limited to 'tonezone.c') diff --git a/tonezone.c b/tonezone.c new file mode 100755 index 0000000..e601de9 --- /dev/null +++ b/tonezone.c @@ -0,0 +1,412 @@ +/* + * BSD Telephony Of Mexico "Tormenta" Tone Zone Support 2/22/01 + * + * Working with the "Tormenta ISA" Card + * + * This program is free software; you can redistribute it and/or modify + * it under thet erms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Primary Author: Mark Spencer + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "tonezone.h" + +#define DEFAULT_ZT_DEV "/dev/zap/ctl" + +#define MAX_SIZE 16384 +#define CLIP 32635 +#define BIAS 0x84 + +static float loudness=8192.0; + +unsigned char +linear2ulaw(sample) +short sample; { + static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7}; + int sign, exponent, mantissa; + unsigned char ulawbyte; + + /* Get the sample into sign-magnitude. */ + sign = (sample >> 8) & 0x80; /* set aside the sign */ + if (sign != 0) sample = -sample; /* get magnitude */ + if (sample > CLIP) sample = CLIP; /* clip the magnitude */ + + /* Convert from 16 bit linear to ulaw. */ + sample = sample + BIAS; + exponent = exp_lut[(sample >> 7) & 0xFF]; + mantissa = (sample >> (exponent + 3)) & 0x0F; + ulawbyte = ~(sign | (exponent << 4) | mantissa); +#ifdef ZEROTRAP + if (ulawbyte == 0) ulawbyte = 0x02; /* optional CCITT trap */ +#endif + + return(ulawbyte); +} + + + +static int calc_samples(int freq) +{ + int x, samples; + /* Calculate the number of samples at 8000hz sampling + we need to have this wave form */ + samples = 8000; + /* Take out common 2's up to six times */ + for (x=0;x<6;x++) + if (!(freq % 2)) { + freq /= 2; + samples /= 2; + } + /* Take out common 5's (up to three times */ + for (x=0;x<3;x++) + if (!(freq % 5)) { + freq /= 5; + samples /=5; + } + /* No more common factors. */ + return samples; +} + + + +struct tone_zone *tone_zone_find(char *country) +{ + struct tone_zone *z; + z = builtin_zones; + while(z->zone > -1) { + if (!strcasecmp(country, z->country)) + return z; + z++; + } + return NULL; +} + +struct tone_zone *tone_zone_find_by_num(int id) +{ + struct tone_zone *z; + z = builtin_zones; + while(z->zone > -1) { + if (z->zone == id) + return z; + z++; + } + return NULL; +} + +static int build_tone(char *data, int size, struct tone_zone_sound *t, int *count) +{ + char *dup, *s; + struct zt_tone_def *td=NULL; + int firstnobang = -1; + int freq1, freq2, time; + int samples, samples1, samples2; + int x; + int used = 0; + float val; + dup = strdup(t->data); + s = strtok(dup, ","); + while(s && strlen(s)) { + /* Handle optional ! which signifies don't start here*/ + if (s[0] == '!') + s++; + else if (firstnobang < 0) { +#if 0 + printf("First no bang: %s\n", s); +#endif + firstnobang = *count; + } + if (sscanf(s, "%d+%d/%d", &freq1, &freq2, &time) == 3) { + /* f1+f2/time format */ +#if 0 + printf("f1+f2/time format: %d, %d, %d\n", freq1, freq2, time); +#endif + } else if (sscanf(s, "%d+%d", &freq1, &freq2) == 2) { +#if 0 + printf("f1+f2 format: %d, %d\n", freq1, freq2); +#endif + time = 0; + } else if (sscanf(s, "%d/%d", &freq1, &time) == 2) { +#if 0 + printf("f1/time format: %d, %d\n", freq1, time); +#endif + freq2 = 0; + } else if (sscanf(s, "%d", &freq1) == 1) { +#if 0 + printf("f1 format: %d\n", freq1); +#endif + firstnobang = *count; + freq2 = 0; + time = 0; + } else { + fprintf(stderr, "tone component '%s' of '%s' is a syntax error\n", s,t->data); + return -1; + } + if (freq1) + samples1 = calc_samples(freq1); + else + samples1 = 40; + if (freq2) + samples2 = calc_samples(freq2); + else + samples2 = 0; + samples = samples1; + if (freq2) { + while(samples % samples2) + samples += samples1; + } +#if 0 + printf("Using %d samples for %d and %d\n", samples, freq1, freq2); +#endif + if (size < samples + sizeof(struct zt_tone_def)) { + fprintf(stderr, "Not enough space for samples\n"); + return -1; + } + td = (struct zt_tone_def *)data; + data += (sizeof(struct zt_tone_def) + samples); + used += (sizeof(struct zt_tone_def) + samples); + size -= (sizeof(struct zt_tone_def) + samples); + td->size = samples; + td->tone = t->toneid; + if (time) { + /* We should move to the next tone */ + td->next = *count + 1; + td->samples = time * 8; + } else { + /* Stay with us */ + td->next = *count; + td->samples = samples; + } + for (x=0;xdata[x] = linear2ulaw((int)val); + } + (*count)++; + s = strtok(NULL, ","); + } + if (td && time) { + /* If we don't end on a solid tone, return */ + td->next = firstnobang; + } + return used; +} + +char *tone_zone_tone_name(int id) +{ + static char tmp[80]; + switch(id) { + case ZT_TONE_DIALTONE: + return "Dialtone"; + case ZT_TONE_BUSY: + return "Busy"; + case ZT_TONE_RINGTONE: + return "Ringtone"; + case ZT_TONE_CONGESTION: + return "Congestion"; + case ZT_TONE_CALLWAIT: + return "Call Waiting"; + case ZT_TONE_DIALRECALL: + return "Dial Recall"; + case ZT_TONE_RECORDTONE: + return "Record Tone"; + case ZT_TONE_CUST1: + return "Custom 1"; + case ZT_TONE_CUST2: + return "Custom 2"; + case ZT_TONE_INFO: + return "Special Information"; + default: + snprintf(tmp, sizeof(tmp), "Unknown tone %d", id); + return tmp; + } +} + +#ifdef TONEZONE_DRIVER +static void dump_tone_zone(void *data) +{ + struct zt_tone_def_header *z; + struct zt_tone_def *td; + int x; + int len=0; + z = data; + data += sizeof(*z); + printf("Header: %d tones, %d bytes of data, zone %d (%s)\n", + z->count, z->size, z->zone, z->name); + for (x=0;x < z->count; x++) { + td = data; + printf("Tone Fragment %d: %d bytes, %s tone, next is %d, %d samples total\n", + x, td->size, tone_name(td->tone), td->next, td->samples); + data += sizeof(*td); + data += td->size; + len += td->size; + } + printf("Total measured bytes of data: %d\n", len); +} +#endif + +int tone_zone_register_zone(int fd, struct tone_zone *z) +{ + char buf[MAX_SIZE]; + int res; + int count=0; + int x; + int used = 0; + int iopenedit = 0; + int space = MAX_SIZE; + char *ptr = buf; + struct zt_tone_def_header *h; + if (fd < 0) { + fd = open(DEFAULT_ZT_DEV, O_RDWR); + iopenedit=1; + if (fd < 0) { + fprintf(stderr, "Unable to open %s and fd not provided\n", DEFAULT_ZT_DEV); + return -1; + } + } + h = (struct zt_tone_def_header *)ptr; + ptr += sizeof(struct zt_tone_def_header); + space -= sizeof(struct zt_tone_def_header); + used += sizeof(struct zt_tone_def_header); + /* + * Fill in ring cadence + */ + for (x=0;xringcadence[x] = z->ringcadence[x]; + /* Put in an appropriate method for a kernel ioctl */ + for (x=0;xtones[x].data)) { + /* It's a real tone */ +#if 0 + printf("Tone: %d, string: %s\n", z->tones[x].toneid, z->tones[x].data); +#endif + res = build_tone(ptr, space, &z->tones[x], &count); + if (res < 0) { + fprintf(stderr, "Tone not built.\n"); + if (iopenedit) + close(fd); + return -1; + } + ptr += res; + used += res; + space -= res; + } + } + h->count = count; + h->size = used - sizeof(struct zt_tone_def_header) - count * sizeof(struct zt_tone_def); + h->zone = z->zone; + strncpy(h->name, z->description, sizeof(h->name)); + x = z->zone; + ioctl(fd, ZT_FREEZONE, &x); + res = ioctl(fd, ZT_LOADZONE, h); + if (res) + fprintf(stderr, "ioctl(ZT_LOADZONE) failed: %s\n", strerror(errno)); + if (iopenedit) + close(fd); + return res; +} + +int tone_zone_register(int fd, char *country) +{ + struct tone_zone *z; + z = tone_zone_find(country); + if (z) { + return tone_zone_register_zone(-1, z); + } else { + return -1; + } +} + + + +int tone_zone_set_zone(int fd, char *country) +{ + int res=-1; + struct tone_zone *z; + if (fd > -1) { + z = tone_zone_find(country); + if (z) + res = ioctl(fd, ZT_SETTONEZONE, &z->zone); + if ((res < 0) && (errno == ENODATA)) { + tone_zone_register_zone(fd, z); + res = ioctl(fd, ZT_SETTONEZONE, &z->zone); + } + } + return res; +} + +int tone_zone_get_zone(int fd) +{ + int x=-1; + if (fd > -1) { + ioctl(fd, ZT_GETTONEZONE, &x); + return x; + } + return -1; +} + +int tone_zone_play_tone(int fd, int tone) +{ + struct tone_zone *z; + int res = -1; + int zone; +#if 0 + fprintf(stderr, "Playing tone %d (%s) on %d\n", tone, tone_zone_tone_name(tone), fd); +#endif + if (fd > -1) { + res = ioctl(fd, ZT_SENDTONE, &tone); + if ((res < 0) && (errno == ENODATA)) { + ioctl(fd, ZT_GETTONEZONE, &zone); + z = tone_zone_find_by_num(zone); + if (z) { + res = tone_zone_register_zone(fd, z); + /* Recall the zone */ + ioctl(fd, ZT_SETTONEZONE, &zone); + if (res < 0) { + fprintf(stderr, "Failed to register zone '%s': %s\n", z->description, strerror(errno)); + } else { + res = ioctl(fd, ZT_SENDTONE, &tone); + } + } else + fprintf(stderr, "Don't know anything about zone %d\n", zone); + } + } + return res; +} -- cgit v1.2.3