/* * Configuration program for Zapata Telephony Interface * * Written by Mark Spencer * Based on previous works, designs, and architectures conceived and * written by Jim Dixon . * * Copyright (C) 2001 Jim Dixon / Zapata Telephony. * Copyright (C) 2001 Linux Support Services, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include #include #include #ifdef STANDALONE_ZAPATA #include "kernel/zaptel.h" #include "tonezone.h" #else #include #include #endif #include "ztcfg.h" #define NUM_SPANS ZT_MAX_SPANS /* Assume no more than 1024 dynamics */ #define NUM_DYNAMIC 1024 static int lineno=0; static FILE *cf; static char *filename=CONFIG_FILENAME; #define DEBUG_READER (1 << 0) #define DEBUG_PARSER (1 << 1) #define DEBUG_APPLY (1 << 2) static int debug = 0; static int errcnt = 0; static int deftonezone = -1; static struct zt_lineconfig lc[ZT_MAX_SPANS]; static struct zt_chanconfig cc[ZT_MAX_CHANNELS]; static struct zt_sfconfig sf[ZT_MAX_CHANNELS]; static struct zt_dynamic_span zds[NUM_DYNAMIC]; static char *sig[ZT_MAX_CHANNELS]; /* Signalling */ static int slineno[ZT_MAX_CHANNELS]; /* Line number where signalling specified */ static int spans=0; static int fo_real = 1; static int verbose = 0; static int stopmode = 0; static int numdynamic = 0; static char zonestoload[ZT_TONE_ZONE_MAX][10]; static int numzones = 0; static char *lbostr[] = { "0 db (CSU)/0-133 feet (DSX-1)", "133-266 feet (DSX-1)", "266-399 feet (DSX-1)", "399-533 feet (DSX-1)", "533-655 feet (DSX-1)", "-7.5db (CSU)", "-15db (CSU)", "-22.5db (CSU)" }; static char *laws[] = { "Default", "Mu-law", "A-law" }; static int error(char *fmt, ...) { int res; static int shown=0; va_list ap; if (!shown) { fprintf(stderr, "Notice: Configuration file is %s\n", filename); shown++; } res = fprintf(stderr, "line %d: ", lineno); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); errcnt++; return res; } static void trim(char *buf) { /* Trim off trailing spaces, tabs, etc */ while(strlen(buf) && (buf[strlen(buf) -1] < 33)) buf[strlen(buf) -1] = '\0'; } static int parseargs(char *input, char *output[], int maxargs, char sep) { char *c; int pos=0; c = input; output[pos++] = c; while(*c) { while(*c && (*c != sep)) c++; if (*c) { *c = '\0'; c++; while(*c && (*c < 33)) c++; if (*c) { if (pos >= maxargs) return -1; output[pos] = c; trim(output[pos]); pos++; output[pos] = NULL; /* Return error if we have too many */ } else return pos; } } return pos; } int dspanconfig(char *keyword, char *args) { static char *realargs[10]; int argc; int res; int chans; int timing; argc = res = parseargs(args, realargs, 4, ','); if (res != 4) { error("Incorrect number of arguments to 'dynamic' (should be ,
,, )\n"); } res = sscanf(realargs[2], "%d", &chans); if ((res == 1) && (chans < 1)) res = -1; if (res != 1) { error("Invalid number of channels '%s', should be a number > 0.\n", realargs[2]); } res = sscanf(realargs[3], "%d", &timing); if ((res == 1) && (timing < 0)) res = -1; if (res != 1) { error("Invalid timing '%s', should be a number > 0.\n", realargs[3]); } zap_copy_string(zds[numdynamic].driver, realargs[0], sizeof(zds[numdynamic].driver)); zap_copy_string(zds[numdynamic].addr, realargs[1], sizeof(zds[numdynamic].addr)); zds[numdynamic].numchans = chans; zds[numdynamic].timing = timing; numdynamic++; return 0; } int spanconfig(char *keyword, char *args) { static char *realargs[10]; int res; int argc; int span; int timing; argc = res = parseargs(args, realargs, 6, ','); if ((res < 5) || (res > 6)) { error("Incorrect number of arguments to 'span' (should be ,,,,[,yellow])\n"); } res = sscanf(realargs[0], "%i", &span); if (res != 1) { error("Span number should be a valid span number, not '%s'\n", realargs[0]); return -1; } res = sscanf(realargs[1], "%i", &timing); if ((res != 1) || (timing < 0) || (timing > 15)) { error("Timing should be a number from 0 to 15, not '%s'\n", realargs[1]); return -1; } res = sscanf(realargs[2], "%i", &lc[spans].lbo); if (res != 1) { error("Line build-out (LBO) should be a number from 0 to 7 (usually 0) not '%s'\n", realargs[2]); return -1; } if ((lc[spans].lbo < 0) || (lc[spans].lbo > 7)) { error("Line build-out should be in the range 0 to 7, not %d\n", lc[spans].lbo); return -1; } if (!strcasecmp(realargs[3], "d4")) { lc[spans].lineconfig |= ZT_CONFIG_D4; lc[spans].lineconfig &= ~ZT_CONFIG_ESF; lc[spans].lineconfig &= ~ZT_CONFIG_CCS; } else if (!strcasecmp(realargs[3], "esf")) { lc[spans].lineconfig |= ZT_CONFIG_ESF; lc[spans].lineconfig &= ~ZT_CONFIG_D4; lc[spans].lineconfig &= ~ZT_CONFIG_CCS; } else if (!strcasecmp(realargs[3], "ccs")) { lc[spans].lineconfig |= ZT_CONFIG_CCS; lc[spans].lineconfig &= ~(ZT_CONFIG_ESF | ZT_CONFIG_D4); } else if (!strcasecmp(realargs[3], "cas")) { lc[spans].lineconfig &= ~ZT_CONFIG_CCS; lc[spans].lineconfig &= ~(ZT_CONFIG_ESF | ZT_CONFIG_D4); } else { error("Framing(T1)/Signalling(E1) must be one of 'd4', 'esf', 'cas' or 'ccs', not '%s'\n", realargs[3]); return -1; } if (!strcasecmp(realargs[4], "ami")) { lc[spans].lineconfig &= ~(ZT_CONFIG_B8ZS | ZT_CONFIG_HDB3); lc[spans].lineconfig |= ZT_CONFIG_AMI; } else if (!strcasecmp(realargs[4], "b8zs")) { lc[spans].lineconfig |= ZT_CONFIG_B8ZS; lc[spans].lineconfig &= ~(ZT_CONFIG_AMI | ZT_CONFIG_HDB3); } else if (!strcasecmp(realargs[4], "hdb3")) { lc[spans].lineconfig |= ZT_CONFIG_HDB3; lc[spans].lineconfig &= ~(ZT_CONFIG_AMI | ZT_CONFIG_B8ZS); } else { error("Coding must be one of 'ami', 'b8zs' or 'hdb3', not '%s'\n", realargs[4]); return -1; } if (argc > 5) { if (!strcasecmp(realargs[5], "yellow")) lc[spans].lineconfig |= ZT_CONFIG_NOTOPEN; else if (!strcasecmp(realargs[5], "crc4")) { lc[spans].lineconfig |= ZT_CONFIG_CRC4; } else { error("Only valid fifth arguments are 'yellow' or 'crc4', not '%s'\n", realargs[5]); return -1; } } if (argc > 6) { if (!strcasecmp(realargs[6], "yellow")) lc[spans].lineconfig |= ZT_CONFIG_NOTOPEN; else { error("Only valid sixth argument is 'yellow', not '%s'\n", realargs[6]); return -1; } } lc[spans].span = spans + 1; lc[spans].sync = timing; /* Valid span */ spans++; return 0; } int apply_channels(int chans[], char *argstr) { char *args[ZT_MAX_CHANNELS+1]; char *range[3]; int res,x, res2,y; int chan; int start, finish; char argcopy[256]; res = parseargs(argstr, args, ZT_MAX_CHANNELS, ','); if (res < 0) error("Too many arguments... Max is %d\n", ZT_MAX_CHANNELS); for (x=0;x-.\n", args[x]); return -1; } res2 =sscanf(range[0], "%i", &start); if (res2 != 1) { error("Syntax error. Start of range '%s' should be a number from 1 to %d\n", args[x], ZT_MAX_CHANNELS - 1); return -1; } else if ((start < 1) || (start >= ZT_MAX_CHANNELS)) { error("Start of range '%s' must be between 1 and %d (not '%d')\n", args[x], ZT_MAX_CHANNELS - 1, start); return -1; } res2 =sscanf(range[1], "%i", &finish); if (res2 != 1) { error("Syntax error. End of range '%s' should be a number from 1 to %d\n", args[x], ZT_MAX_CHANNELS - 1); return -1; } else if ((finish < 1) || (finish >= ZT_MAX_CHANNELS)) { error("end of range '%s' must be between 1 and %d (not '%d')\n", args[x], ZT_MAX_CHANNELS - 1, finish); return -1; } if (start > finish) { error("Range '%s' should start before it ends\n", args[x]); return -1; } for (y=start;y<=finish;y++) chans[y]=1; } else { /* It's a single channel */ res2 =sscanf(args[x], "%i", &chan); if (res2 != 1) { error("Syntax error. Channel should be a number from 1 to %d, not '%s'\n", ZT_MAX_CHANNELS - 1, args[x]); return -1; } else if ((chan < 1) || (chan >= ZT_MAX_CHANNELS)) { error("Channel must be between 1 and %d (not '%d')\n", ZT_MAX_CHANNELS - 1, chan); return -1; } chans[chan]=1; } } return res; } int parse_idle(int *i, char *s) { char a,b,c,d; if (s) { if (sscanf(s, "%c%c%c%c", &a,&b,&c,&d) == 4) { if (((a == '0') || (a == '1')) && ((b == '0') || (b == '1')) && ((c == '0') || (c == '1')) && ((d == '0') || (d == '1'))) { *i = 0; if (a == '1') *i |= ZT_ABIT; if (b == '1') *i |= ZT_BBIT; if (c == '1') *i |= ZT_CBIT; if (d == '1') *i |= ZT_DBIT; return 0; } } } error("CAS Signalling requires idle definition in the form ':xxxx' at the end of the channel definition, where xxxx represent the a, b, c, and d bits\n"); return -1; } void mknotch(float freq, float bw, long *p1, long *p2, long *p3); static void mktxtone(float freq, float l, int *fac, int *init_v2, int *init_v3) { float gain; /* Bring it down -8 dbm */ gain = pow(10.0, (l - 3.14) / 20.0) * 65536.0 / 2.0; *fac = 2.0 * cos(2.0 * M_PI * (freq / 8000.0)) * 32768.0; *init_v2 = sin(-4.0 * M_PI * (freq / 8000.0)) * gain; *init_v3 = sin(-2.0 * M_PI * (freq / 8000.0)) * gain; } static int parse_sf(struct zt_sfconfig *sf, char *str) { char *realargs[10],*args; int res; float rxfreq,rxbw,txfreq,txlevel; int flags = 0; args = strdup(str); res = parseargs(args, realargs, 6, ','); if (res != 6) { error("Incorrect number of arguments to 'sf' (should be :,,,,,)\n"); free(args); return -1; } res = sscanf(realargs[0],"%f",&rxfreq); if ((res < 1) || (rxfreq && ((rxfreq < 100.0) || (rxfreq >= 4000.0)))) { error("Invalid rx freq. specification (should be between 100.0 and 4000.0 hertz\n"); free(args); return -1; } res = sscanf(realargs[1],"%f",&rxbw); if ((res < 1) || (rxfreq && ((rxbw < 5.0) || (rxbw >= 1000.0)))) { error("Invalid rx bandwidth specification (should be between 5.0 and 1000.0 hertz\n"); free(args); return -1; } res = sscanf(realargs[3],"%f",&txfreq); if ((res < 1) || (txfreq && ((txfreq < 100.0) || (txfreq >= 4000.0)))) { error("Invalid tx freq. specification (should be between 100.0 and 4000.0 hertz\n"); free(args); return -1; } res = sscanf(realargs[4],"%f",&txlevel); if ((res < 1) || (txfreq && ((txlevel < -50.0) || (txlevel > 3.0)))) { error("Invalid tx level specification (should be between -50.0 and 3.0 dbm\n"); free(args); return -1; } if ((*realargs[2] == 'i') || (*realargs[2] == 'I') || (*realargs[2] == 'r') || (*realargs[2] == 'R')) flags |= ZT_REVERSE_RXTONE; if ((*realargs[5] == 'i') || (*realargs[5] == 'I') || (*realargs[5] == 'r') || (*realargs[5] == 'R')) flags |= ZT_REVERSE_TXTONE; if (rxfreq) mknotch(rxfreq,rxbw,&sf->rxp1,&sf->rxp2,&sf->rxp3); if (txfreq) mktxtone(txfreq,txlevel,&sf->txtone,&sf->tx_v2,&sf->tx_v3); sf->toneflag = flags; free(args); return 0; } static int chanconfig(char *keyword, char *args) { int chans[ZT_MAX_CHANNELS]; int res; int x; int master=0; char *idle; bzero(chans, sizeof(chans)); strtok(args, ":"); idle = strtok(NULL, ":"); res = apply_channels(chans, args); if (res <= 0) return -1; for (x=1;x= ZT_TONE_ZONE_MAX) { error("Too many tone zones specified\n"); return 0; } zap_copy_string(zonestoload[numzones++], args, sizeof(zonestoload[0])); return 0; } static int defaultzone(char *keyword, char *args) { struct tone_zone *z; if (!(z = tone_zone_find(args))) { error("No such tone zone known: %s\n", args); return 0; } deftonezone = z->zone; return 0; } #if 0 static int unimplemented(char *keyword, char *args) { fprintf(stderr, "Warning: '%s' is not yet implemented\n", keyword); return 0; } #endif static void printconfig() { int x,y; int ps; int configs=0; printf("\nZaptel Configuration\n" "======================\n\n"); for (x=0;x 1) { printf("\nChannel map:\n\n"); for (x=1;x -- Use instead of " CONFIG_FILENAME "\n" " -h -- Generate this help statement\n" " -v -- Verbose (more -v's means more verbose)\n" " -t -- Test mode only, do not apply\n" " -s -- Shutdown spans only\n" ,c); exit(exitcode); } int main(int argc, char *argv[]) { char c; char *buf; char *key, *value; int x,found; int fd; while((c = getopt(argc, argv, "hc:vs")) != -1) { switch(c) { case 'c': filename=optarg; break; case 'h': usage(argv[0], 0); break; case '?': usage(argv[0], 1); break; case 'v': verbose++; break; case 't': fo_real = 0; break; case 's': stopmode = 1; break; } } cf = fopen(filename, "r"); if (cf) { while((buf = readline())) { if (debug & DEBUG_READER) fprintf(stderr, "Line %d: %s\n", lineno, buf); key = value = buf; while(value && *value && (*value != '=')) value++; if (value) *value='\0'; if (value) value++; while(value && *value && (*value < 33)) value++; if (*value) { trim(key); if (debug & DEBUG_PARSER) fprintf(stderr, "Keyword: [%s], Value: [%s]\n", key, value); } else error("Syntax error. Should be =\n"); found=0; for (x=0;x\n"); fclose(cf); } else { error("Unable to open configuration file '%s'\n", filename); } if (!errcnt) { if (verbose) { printconfig(); } if (fo_real) { if (debug & DEBUG_APPLY) { printf("About to open Master device\n"); fflush(stdout); } fd = open(MASTER_DEVICE, O_RDWR); if (fd < 0) error("Unable to open master device '%s'\n", MASTER_DEVICE); else { for (x=0;x -1) { if (ioctl(fd, ZT_DEFAULTZONE, &deftonezone)) { fprintf(stderr, "ZT_DEFAULTZONE failed: %s (%d)\n", strerror(errno), errno); close(fd); exit(1); } } for (x=0;x