dahdi-tools/dahdi_cfg.c

1932 lines
46 KiB
C
Raw Normal View History

/*
* Configuration program for DAHDI Telephony Interface
*
* Written by Mark Spencer <markster@digium.com>
* Based on previous works, designs, and architectures conceived and
* written by Jim Dixon <jim@lambdatel.com>.
*
* Copyright (C) 2001 Jim Dixon / Zapata Telephony.
* Copyright (C) 2001-2008 Digium, Inc.
*
* All rights reserved.
*
* Primary Author: Mark Spencer <markster@digium.com>
* Radio Support by Jim Dixon <jim@lambdatel.com>
*/
/*
* 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 <stdio.h>
#include <getopt.h>
#include <signal.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <errno.h>
#include <dirent.h>
#include <stdbool.h>
#include <dahdi/user.h>
#include "tonezone.h"
#include "dahdi_tools_version.h"
#define CONFIG_FILENAME "/etc/dahdi/system.conf"
#define MASTER_DEVICE "/dev/dahdi/ctl"
#define NUM_SPANS DAHDI_MAX_SPANS
#define NUM_TONES 15
/*! A sanity check for the timing parameter of the span.
*
* Note that each driver using it is still responsible for validating
* that value.
*/
#define MAX_TIMING 255
/* Assume no more than 1024 dynamics */
#define NUM_DYNAMIC 1024
static int lineno=0;
static FILE *cf;
static char *filename=CONFIG_FILENAME;
int rxtones[NUM_TONES + 1],rxtags[NUM_TONES + 1],txtones[NUM_TONES + 1];
int bursttime = 0, debouncetime = 0, invertcor = 0, exttone = 0, corthresh = 0;
int txgain = 0, rxgain = 0, deemp = 0, preemp = 0;
int corthreshes[] = {3125,6250,9375,12500,15625,18750,21875,25000,0} ;
static int toneindex = 1;
#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 dahdi_lineconfig lc[DAHDI_MAX_SPANS];
static struct dahdi_chanconfig cc[DAHDI_MAX_CHANNELS];
static int only_span = 0;
static int restrict_channels = 0;
static int selected_channels[DAHDI_MAX_CHANNELS];
static int declared_spans[DAHDI_MAX_SPANS];
static struct dahdi_attach_echocan ae[DAHDI_MAX_CHANNELS];
static struct dahdi_dynamic_span zds[NUM_DYNAMIC];
static const char *sig[DAHDI_MAX_CHANNELS]; /* Signalling */
static int slineno[DAHDI_MAX_CHANNELS]; /* Line number where signalling specified */
static int fiftysixkhdlc[DAHDI_MAX_CHANNELS];
static int spans=0;
static int dry_run = 0;
static int verbose = 0;
static int force = 0;
static int stopmode = 0;
static int numdynamic = 0;
static char zonestoload[DAHDI_TONE_ZONE_MAX][10];
static int numzones = 0;
static int fd = -1;
static const 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 const char *laws[] = {
"Default",
"Mu-law",
"A-law"
};
static bool _are_all_spans_assigned(const char *device_path)
{
char attribute[1024];
int res;
FILE *fp;
int span_count;
DIR *dirp;
struct dirent *dirent;
snprintf(attribute, sizeof(attribute) - 1,
"%s/span_count", device_path);
fp = fopen(attribute, "r");
if (NULL == fp) {
fprintf(stderr, "Failed to open '%s'.\n", attribute);
return false;
}
res = fscanf(fp, "%d", &span_count);
fclose(fp);
if (EOF == res) {
fprintf(stderr, "Failed to read '%s'.\n", attribute);
return false;
}
dirp = opendir(device_path);
while (span_count) {
dirent = readdir(dirp);
if (NULL == dirent)
break;
if (!strncmp("span-", dirent->d_name, 5)) {
--span_count;
}
}
closedir(dirp);
return (span_count > 0) ? false : true;
}
/**
* are_all_spans_assigned - Look in sysfs to see if all spans for a device are assigned.
*
* Returns true if there are $span_count child spans of all devices, or false
* otherwise.
*/
static bool are_all_spans_assigned(void)
{
DIR *dirp;
struct dirent *dirent;
bool res = true;
char device_path[1024];
dirp = opendir("/sys/bus/dahdi_devices/devices");
if (!dirp) {
/* If we cannot open dahdi_devices, either dahdi isn't loaded,
* or we're using an older version of DAHDI that doesn't use
* sysfs. */
return true;
}
while (true && res) {
dirent = readdir(dirp);
if (NULL == dirent)
break;
if (!strcmp(dirent->d_name, ".") ||
!strcmp(dirent->d_name, ".."))
continue;
snprintf(device_path, sizeof(device_path)-1,
"/sys/bus/dahdi_devices/devices/%s", dirent->d_name);
res = _are_all_spans_assigned(device_path);
}
closedir(dirp);
errno = 0;
return res;
}
static bool wait_for_all_spans_assigned(unsigned long timeout_sec)
{
bool all_assigned = are_all_spans_assigned();
unsigned int timeout = 10*timeout_sec;
while (!all_assigned && --timeout) {
usleep(100000);
all_assigned = are_all_spans_assigned();
}
return all_assigned;
}
static const char *sigtype_to_str(const int sig)
{
switch (sig) {
case 0:
return "Unused";
case DAHDI_SIG_EM:
return "E & M";
case DAHDI_SIG_EM_E1:
return "E & M E1";
case DAHDI_SIG_FXSLS:
return "FXS Loopstart";
case DAHDI_SIG_FXSGS:
return "FXS Groundstart";
case DAHDI_SIG_FXSKS:
return "FXS Kewlstart";
case DAHDI_SIG_FXOLS:
return "FXO Loopstart";
case DAHDI_SIG_FXOGS:
return "FXO Groundstart";
case DAHDI_SIG_FXOKS:
return "FXO Kewlstart";
case DAHDI_SIG_CAS:
return "CAS / User";
case DAHDI_SIG_DACS:
return "DACS";
case DAHDI_SIG_DACS_RBS:
return "DACS w/RBS";
case DAHDI_SIG_CLEAR:
return "Clear channel";
case DAHDI_SIG_SLAVE:
return "Slave channel";
case DAHDI_SIG_HDLCRAW:
return "Raw HDLC";
case DAHDI_SIG_HDLCNET:
return "Network HDLC";
case DAHDI_SIG_HDLCFCS:
return "HDLC with FCS check";
case DAHDI_SIG_HARDHDLC:
return "Hardware assisted D-channel";
case DAHDI_SIG_MTP2:
return "MTP2";
default:
return "Unknown";
}
}
static void clear_fields()
{
memset(rxtones,0,sizeof(rxtones));
memset(rxtags,0,sizeof(rxtags));
memset(txtones,0,sizeof(txtones));
bursttime = 0;
debouncetime = 0;
invertcor = 0;
exttone = 0;
txgain = 0;
rxgain = 0;
deemp = 0;
preemp = 0;
}
static int error(char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
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 char *trim(char *buf)
{
size_t len;
while (*buf && (*buf < 33)) {
buf++;
}
len = strlen(buf);
while (len && buf[len-1] < 33) {
buf[--len] = '\0';
}
return buf;
}
static int skip_channel(int x)
{
if (restrict_channels) {
if (!selected_channels[x])
return 1;
} else {
if (only_span && !declared_spans[only_span]) {
fprintf(stderr,
"Error: analog span %d given to '-S', without '-C' restriction.\n",
only_span);
exit(1);
}
}
return 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 res;
int chans;
int timing;
res = parseargs(args, realargs, 4, ',');
if (res != 4) {
error("Incorrect number of arguments to 'dynamic' (should be <driver>,<address>,<num channels>, <timing>)\n");
return -1;
}
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]);
return -1;
}
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]);
return -1;
}
dahdi_copy_string(zds[numdynamic].driver, realargs[0], sizeof(zds[numdynamic].driver));
dahdi_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;
int i;
argc = res = parseargs(args, realargs, 9, ',');
if ((res < 5) || (res > 9)) {
error("Incorrect number of arguments to 'span' (should be <spanno>,<timing>,<lbo>,<framing>,<coding>[, crc4 | yellow [, yellow]])\n");
return -1;
}
res = sscanf(realargs[0], "%d", &span);
if (res != 1) {
error("Span number should be a valid span number, not '%s'\n", realargs[0]);
return -1;
}
declared_spans[span] = 1;
res = sscanf(realargs[1], "%d", &timing);
if ((res != 1) || (timing < 0) || (timing > MAX_TIMING)) {
error("Timing should be a number from 0 to %d, not '%s'\n",
MAX_TIMING, realargs[1]);
return -1;
}
res = sscanf(realargs[2], "%d", &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 |= DAHDI_CONFIG_D4;
lc[spans].lineconfig &= ~DAHDI_CONFIG_ESF;
lc[spans].lineconfig &= ~DAHDI_CONFIG_CCS;
} else if (!strcasecmp(realargs[3], "esf")) {
lc[spans].lineconfig |= DAHDI_CONFIG_ESF;
lc[spans].lineconfig &= ~DAHDI_CONFIG_D4;
lc[spans].lineconfig &= ~DAHDI_CONFIG_CCS;
} else if (!strcasecmp(realargs[3], "ccs")) {
lc[spans].lineconfig |= DAHDI_CONFIG_CCS;
lc[spans].lineconfig &= ~(DAHDI_CONFIG_ESF | DAHDI_CONFIG_D4);
} else if (!strcasecmp(realargs[3], "cas")) {
lc[spans].lineconfig &= ~DAHDI_CONFIG_CCS;
lc[spans].lineconfig &= ~(DAHDI_CONFIG_ESF | DAHDI_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 &= ~(DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_HDB3);
lc[spans].lineconfig |= DAHDI_CONFIG_AMI;
} else if (!strcasecmp(realargs[4], "b8zs")) {
lc[spans].lineconfig |= DAHDI_CONFIG_B8ZS;
lc[spans].lineconfig &= ~(DAHDI_CONFIG_AMI | DAHDI_CONFIG_HDB3);
} else if (!strcasecmp(realargs[4], "hdb3")) {
lc[spans].lineconfig |= DAHDI_CONFIG_HDB3;
lc[spans].lineconfig &= ~(DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS);
} else {
error("Coding must be one of 'ami', 'b8zs' or 'hdb3', not '%s'\n", realargs[4]);
return -1;
}
for (i = 5; i < argc; i++) {
if (!strcasecmp(realargs[i], "yellow"))
lc[spans].lineconfig |= DAHDI_CONFIG_NOTOPEN;
else if (!strcasecmp(realargs[i], "crc4"))
lc[spans].lineconfig |= DAHDI_CONFIG_CRC4;
else if (!strcasecmp(realargs[i], "nt"))
lc[spans].lineconfig |= DAHDI_CONFIG_NTTE;
else if (!strcasecmp(realargs[i], "te"))
lc[spans].lineconfig &= ~DAHDI_CONFIG_NTTE;
else if (!strcasecmp(realargs[i], "term"))
lc[spans].lineconfig |= DAHDI_CONFIG_TERM;
else {
error("Remaining arguments may be any of: 'yellow', 'crc4', 'nt', 'te', 'term', not '%s'\n", realargs[i]);
return -1;
}
}
lc[spans].span = span;
lc[spans].sync = timing;
/* Valid span */
spans++;
return 0;
}
int apply_channels(int chans[], char *argstr)
{
char *args[DAHDI_MAX_CHANNELS+1];
char *range[3];
int res,x, res2,y;
int chan;
int start, finish;
char argcopy[256];
res = parseargs(argstr, args, DAHDI_MAX_CHANNELS, ',');
if (res < 0) {
error("Too many arguments... Max is %d\n", DAHDI_MAX_CHANNELS);
return -1;
}
for (x=0;x<res;x++) {
if (strchr(args[x], '-')) {
/* It's a range */
dahdi_copy_string(argcopy, args[x], sizeof(argcopy));
res2 = parseargs(argcopy, range, 2, '-');
if (res2 != 2) {
error("Syntax error in range '%s'. Should be <val1>-<val2>.\n", args[x]);
return -1;
}
res2 =sscanf(range[0], "%d", &start);
if (res2 != 1) {
error("Syntax error. Start of range '%s' should be a number from 1 to %d\n", args[x], DAHDI_MAX_CHANNELS - 1);
return -1;
} else if ((start < 1) || (start >= DAHDI_MAX_CHANNELS)) {
error("Start of range '%s' must be between 1 and %d (not '%d')\n", args[x], DAHDI_MAX_CHANNELS - 1, start);
return -1;
}
res2 =sscanf(range[1], "%d", &finish);
if (res2 != 1) {
error("Syntax error. End of range '%s' should be a number from 1 to %d\n", args[x], DAHDI_MAX_CHANNELS - 1);
return -1;
} else if ((finish < 1) || (finish >= DAHDI_MAX_CHANNELS)) {
error("end of range '%s' must be between 1 and %d (not '%d')\n", args[x], DAHDI_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], "%d", &chan);
if (res2 != 1) {
error("Syntax error. Channel should be a number from 1 to %d, not '%s'\n", DAHDI_MAX_CHANNELS - 1, args[x]);
return -1;
} else if ((chan < 1) || (chan >= DAHDI_MAX_CHANNELS)) {
error("Channel must be between 1 and %d (not '%d')\n", DAHDI_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 |= DAHDI_ABIT;
if (b == '1')
*i |= DAHDI_BBIT;
if (c == '1')
*i |= DAHDI_CBIT;
if (d == '1')
*i |= DAHDI_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;
}
static int parse_channel(char *channel, int *startchan)
{
if (!channel || (sscanf(channel, "%d", startchan) != 1) ||
(*startchan < 1)) {
error("DACS requires a starting channel in the form ':x' where x is the channel\n");
return -1;
}
return 0;
}
static int chanconfig(char *keyword, char *args)
{
int chans[DAHDI_MAX_CHANNELS];
int res = 0;
int x;
int master=0;
int dacschan = 0;
char *idle;
bzero(chans, sizeof(chans));
strtok(args, ":");
idle = strtok(NULL, ":");
if (!strcasecmp(keyword, "dacs") || !strcasecmp(keyword, "dacsrbs")) {
res = parse_channel(idle, &dacschan);
}
if (!res)
res = apply_channels(chans, args);
if (res <= 0)
return -1;
for (x=1;x<DAHDI_MAX_CHANNELS;x++) {
if (chans[x]) {
if (slineno[x]) {
error("Channel %d already configured as '%s' at line %d\n", x, sig[x], slineno[x]);
continue;
}
if ((!strcasecmp(keyword, "dacs") || !strcasecmp(keyword, "dacsrbs")) && slineno[dacschan]) {
error("DACS Destination channel %d already configured as '%s' at line %d\n", dacschan, sig[dacschan], slineno[dacschan]);
continue;
} else {
cc[dacschan].chan = dacschan;
cc[dacschan].master = dacschan;
slineno[dacschan] = lineno;
}
cc[x].chan = x;
cc[x].master = x;
slineno[x] = lineno;
if (!strcasecmp(keyword, "e&m")) {
cc[x].sigtype = DAHDI_SIG_EM;
sig[x] = sigtype_to_str(cc[x].sigtype);
} else if (!strcasecmp(keyword, "e&me1")) {
cc[x].sigtype = DAHDI_SIG_EM_E1;
sig[x] = sigtype_to_str(cc[x].sigtype);
} else if (!strcasecmp(keyword, "fxsls")) {
cc[x].sigtype = DAHDI_SIG_FXSLS;
sig[x] = sigtype_to_str(cc[x].sigtype);
} else if (!strcasecmp(keyword, "fxsgs")) {
cc[x].sigtype = DAHDI_SIG_FXSGS;
sig[x] = sigtype_to_str(cc[x].sigtype);
} else if (!strcasecmp(keyword, "fxsks")) {
cc[x].sigtype = DAHDI_SIG_FXSKS;
sig[x] = sigtype_to_str(cc[x].sigtype);
} else if (!strcasecmp(keyword, "fxols")) {
cc[x].sigtype = DAHDI_SIG_FXOLS;
sig[x] = sigtype_to_str(cc[x].sigtype);
} else if (!strcasecmp(keyword, "fxogs")) {
cc[x].sigtype = DAHDI_SIG_FXOGS;
sig[x] = sigtype_to_str(cc[x].sigtype);
} else if (!strcasecmp(keyword, "fxoks")) {
cc[x].sigtype = DAHDI_SIG_FXOKS;
sig[x] = sigtype_to_str(cc[x].sigtype);
} else if (!strcasecmp(keyword, "cas") || !strcasecmp(keyword, "user")) {
if (parse_idle(&cc[x].idlebits, idle))
return -1;
cc[x].sigtype = DAHDI_SIG_CAS;
sig[x] = sigtype_to_str(cc[x].sigtype);
} else if (!strcasecmp(keyword, "dacs")) {
/* Setup channel for monitor */
cc[x].idlebits = dacschan;
cc[x].sigtype = DAHDI_SIG_DACS;
sig[x] = sigtype_to_str(cc[x].sigtype);
/* Setup inverse */
cc[dacschan].idlebits = x;
cc[dacschan].sigtype = DAHDI_SIG_DACS;
sig[x] = sigtype_to_str(cc[dacschan].sigtype);
dacschan++;
} else if (!strcasecmp(keyword, "dacsrbs")) {
/* Setup channel for monitor */
cc[x].idlebits = dacschan;
cc[x].sigtype = DAHDI_SIG_DACS_RBS;
sig[x] = sigtype_to_str(cc[x].sigtype);
/* Setup inverse */
cc[dacschan].idlebits = x;
cc[dacschan].sigtype = DAHDI_SIG_DACS_RBS;
sig[x] = sigtype_to_str(cc[dacschan].sigtype);
dacschan++;
} else if (!strcasecmp(keyword, "unused")) {
cc[x].sigtype = 0;
sig[x] = sigtype_to_str(cc[x].sigtype);
} else if (!strcasecmp(keyword, "indclear") || !strcasecmp(keyword, "bchan")) {
cc[x].sigtype = DAHDI_SIG_CLEAR;
sig[x] = sigtype_to_str(cc[x].sigtype);
} else if (!strcasecmp(keyword, "clear")) {
sig[x] = sigtype_to_str(DAHDI_SIG_CLEAR);
if (master) {
cc[x].sigtype = DAHDI_SIG_SLAVE;
cc[x].master = master;
} else {
cc[x].sigtype = DAHDI_SIG_CLEAR;
master = x;
}
} else if (!strcasecmp(keyword, "rawhdlc")) {
sig[x] = sigtype_to_str(DAHDI_SIG_HDLCRAW);
if (master) {
cc[x].sigtype = DAHDI_SIG_SLAVE;
cc[x].master = master;
} else {
cc[x].sigtype = DAHDI_SIG_HDLCRAW;
master = x;
}
} else if (!strcasecmp(keyword, "nethdlc")) {
sig[x] = sigtype_to_str(DAHDI_SIG_HDLCNET);
memset(cc[x].netdev_name, 0, sizeof(cc[x].netdev_name));
if (master) {
cc[x].sigtype = DAHDI_SIG_SLAVE;
cc[x].master = master;
} else {
cc[x].sigtype = DAHDI_SIG_HDLCNET;
if (idle) {
dahdi_copy_string(cc[x].netdev_name, idle, sizeof(cc[x].netdev_name));
}
master = x;
}
} else if (!strcasecmp(keyword, "fcshdlc")) {
sig[x] = sigtype_to_str(DAHDI_SIG_HDLCFCS);
if (master) {
cc[x].sigtype = DAHDI_SIG_SLAVE;
cc[x].master = master;
} else {
cc[x].sigtype = DAHDI_SIG_HDLCFCS;
master = x;
}
} else if (!strcasecmp(keyword, "dchan")) {
sig[x] = "D-channel";
cc[x].sigtype = DAHDI_SIG_HDLCFCS;
} else if (!strcasecmp(keyword, "hardhdlc")) {
sig[x] = "Hardware assisted D-channel";
cc[x].sigtype = DAHDI_SIG_HARDHDLC;
} else if (!strcasecmp(keyword, "mtp2")) {
sig[x] = "MTP2";
cc[x].sigtype = DAHDI_SIG_MTP2;
} else {
fprintf(stderr, "Huh? (%s)\n", keyword);
}
if (cc[x].sigtype != DAHDI_SIG_CAS &&
cc[x].sigtype != DAHDI_SIG_DACS &&
cc[x].sigtype != DAHDI_SIG_DACS_RBS) {
if (NULL != idle) {
fprintf(stderr, "WARNING: idlebits are not valid on %s channels.\n", sig[x]);
}
}
}
}
return 0;
}
static int setlaw(char *keyword, char *args)
{
int res;
int law;
int x;
int chans[DAHDI_MAX_CHANNELS];
bzero(chans, sizeof(chans));
res = apply_channels(chans, args);
if (res <= 0)
return -1;
if (!strcasecmp(keyword, "alaw")) {
law = DAHDI_LAW_ALAW;
} else if (!strcasecmp(keyword, "mulaw")) {
law = DAHDI_LAW_MULAW;
} else if (!strcasecmp(keyword, "deflaw")) {
law = DAHDI_LAW_DEFAULT;
} else {
fprintf(stderr, "Huh??? Don't know about '%s' law\n", keyword);
return -1;
}
for (x=0;x<DAHDI_MAX_CHANNELS;x++) {
if (chans[x])
cc[x].deflaw = law;
}
return 0;
}
static int setfiftysixkhdlc(char *keyword, char *args)
{
int res;
res = apply_channels(fiftysixkhdlc, args);
if (res <= 0)
return -1;
return 0;
}
static int apply_fiftysix(void)
{
int x;
int rate;
int chanfd;
for (x = 1; x < DAHDI_MAX_CHANNELS; x++) {
if (skip_channel(x) || !cc[x].sigtype)
continue;
chanfd = open("/dev/dahdi/channel", O_RDWR);
if (chanfd == -1) {
fprintf(stderr,
"Couldn't open /dev/dahdi/channel: %s\n",
strerror(errno));
return -1;
}
if (ioctl(chanfd, DAHDI_SPECIFY, &x)) {
close(chanfd);
continue;
}
if (fiftysixkhdlc[x]) {
printf("Setting channel %d to 56K mode (only valid on HDLC channels)\n", x);
rate = 56;
} else {
rate = 64;
}
if (ioctl(chanfd, DAHDI_HDLC_RATE, &rate)) {
fprintf(stderr, "Error setting HDLC rate\n");
exit(-1);
}
close(chanfd);
}
return 0;
}
static int setechocan(char *keyword, char *args)
{
int res;
int chans[DAHDI_MAX_CHANNELS] = { 0, };
char *echocan, *chanlist;
unsigned int x;
echocan = strtok(args, ",");
while ((chanlist = strtok(NULL, ","))) {
res = apply_channels(chans, chanlist);
if (res <= 0) {
return -1;
}
}
for (x = 0; x < DAHDI_MAX_CHANNELS; x++) {
if (chans[x]) {
dahdi_copy_string(ae[x].echocan, echocan, sizeof(ae[x].echocan));
}
}
return 0;
}
static int registerzone(char *keyword, char *args)
{
if (numzones >= DAHDI_TONE_ZONE_MAX) {
error("Too many tone zones specified\n");
return 0;
}
dahdi_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
/* Radio functions */
int ctcss(char *keyword, char *args)
{
static char *realargs[10];
int res;
int rxtone;
int rxtag;
int txtone;
int isdcs = 0;
res = parseargs(args, realargs, 3, ',');
if (res != 3) {
error("Incorrect number of arguments to 'ctcss' (should be <rxtone>,<rxtag>,<txtone>)\n");
return -1;
}
res = sscanf(realargs[0], "%d", &rxtone);
if ((res == 1) && (rxtone < 1))
res = -1;
if (res != 1) {
error("Invalid rxtone '%s', should be a number > 0.\n", realargs[0]);
return -1;
}
res = sscanf(realargs[1], "%d", &rxtag);
if ((res == 1) && (rxtag < 0))
res = -1;
if (res != 1) {
error("Invalid rxtag '%s', should be a number > 0.\n", realargs[1]);
return -1;
}
if ((*realargs[2] == 'D') || (*realargs[2] == 'd'))
{
realargs[2]++;
isdcs = 0x8000;
}
res = sscanf(realargs[2], "%d", &txtone);
if ((res == 1) && (rxtag < 0))
res = -1;
if (res != 1) {
error("Invalid txtone '%s', should be a number > 0.\n", realargs[2]);
return -1;
}
if (toneindex >= NUM_TONES)
{
error("Cannot specify more then %d CTCSS tones\n",NUM_TONES);
return -1;
}
rxtones[toneindex] = rxtone;
rxtags[toneindex] = rxtag;
txtones[toneindex] = txtone | isdcs;
toneindex++;
return 0;
}
int dcsrx(char *keyword, char *args)
{
static char *realargs[10];
int res;
int rxtone;
res = parseargs(args, realargs, 1, ',');
if (res != 1) {
error("Incorrect number of arguments to 'dcsrx' (should be <rxtone>)\n");
return -1;
}
res = sscanf(realargs[0], "%d", &rxtone);
if ((res == 1) && (rxtone < 1))
res = -1;
if (res != 1) {
error("Invalid rxtone '%s', should be a number > 0.\n", realargs[0]);
return -1;
}
rxtones[0] = rxtone;
return 0;
}
int tx(char *keyword, char *args)
{
static char *realargs[10];
int res;
int txtone;
int isdcs = 0;
res = parseargs(args, realargs, 1, ',');
if (res != 1) {
error("Incorrect number of arguments to 'tx' (should be <txtone>)\n");
return -1;
}
if ((*realargs[0] == 'D') || (*realargs[0] == 'd'))
{
realargs[0]++;
isdcs = 0x8000;
}
res = sscanf(realargs[0], "%d", &txtone);
if ((res == 1) && (txtone < 1))
res = -1;
if (res != 1) {
error("Invalid tx (tone) '%s', should be a number > 0.\n", realargs[0]);
return -1;
}
txtones[0] = txtone | isdcs;
return 0;
}
int debounce_time(char *keyword, char *args)
{
static char *realargs[10];
int res;
int val;
res = parseargs(args, realargs, 1, ',');
if (res != 1) {
error("Incorrect number of arguments to 'debouncetime' (should be <value>)\n");
return -1;
}
res = sscanf(realargs[0], "%d", &val);
if ((res == 1) && (val < 1))
res = -1;
if (res != 1) {
error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
return -1;
}
debouncetime = val;
return 0;
}
int burst_time(char *keyword, char *args)
{
static char *realargs[10];
int res;
int val;
res = parseargs(args, realargs, 1, ',');
if (res != 1) {
error("Incorrect number of arguments to 'bursttime' (should be <value>)\n");
return -1;
}
res = sscanf(realargs[0], "%d", &val);
if ((res == 1) && (val < 1))
res = -1;
if (res != 1) {
error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
return -1;
}
bursttime = val;
return 0;
}
int tx_gain(char *keyword, char *args)
{
static char *realargs[10];
int res;
int val;
res = parseargs(args, realargs, 1, ',');
if (res != 1) {
error("Incorrect number of arguments to 'txgain' (should be <value>)\n");
return -1;
}
res = sscanf(realargs[0], "%d", &val);
if (res != 1) {
error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
return -1;
}
txgain = val;
return 0;
}
int rx_gain(char *keyword, char *args)
{
static char *realargs[10];
int res;
int val;
res = parseargs(args, realargs, 1, ',');
if (res != 1) {
error("Incorrect number of arguments to 'rxgain' (should be <value>)\n");
return -1;
}
res = sscanf(realargs[0], "%d", &val);
if (res != 1) {
error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
return -1;
}
rxgain = val;
return 0;
}
int de_emp(char *keyword, char *args)
{
static char *realargs[10];