/* * This file and contents thereof are licensed under the terms and * conditions of the GNU Public License version 2. For more information * (including terms and conditions) see http://www.gnu.org/ * * fxotune.c -- A utility for tuning the various settings on the fxo * modules for the TDM400 cards. * * by Matthew Fredrickson * * (C) 2004 Digium, Inc. */ #include #include #include #include #include #include #include #include #include #include #include "wctdm.h" #include "fxotune.h" #include "zaptel.h" static int testduration = 100; /* Test the line for x milliseconds */ static int readduration = 100 * 2; static char *zappath = "/dev/zap"; static char *configfile = "/etc/fxotune.conf"; static char *usage = "Usage: fxotest\n" " -i : Tests for FXO modules and sets echo coefficients\n" " -s : Sets the FXO modules echo coefficients on your system to the best settings\n"; #define OUT_OF_BOUNDS(x) ((x) < 0 || (x) > 255) int process_readbuf(short *ibuf, int isize, short *obuf, int osize) { int i = 0; short *samples = ibuf; short minsample = samples[0]; for (i = 0; i < isize/2; i++) { if (samples[i] < minsample) minsample = samples[i]; } return minsample; } /* Returns index in echocan table with the lowest power pulse readback * -1 means the device is not an FXO module or fails */ int echo_tune(int whichzap) { short bestval = 32355; int bestindex = -1; int i = 0; int res = 0; int total = sizeof(echo_trys) / sizeof(struct wctdm_echo_coefs); int randdev; short *outbuf = NULL, *inbuf = NULL; int obufsize = testduration * 8 * 2; /* In one milisecond there are 8 samples of 2 byte length */ int ibufsize = readduration * 8 * 2; randdev = open("/dev/random", O_RDONLY); if (randdev < 0) { fprintf(stdout, "Unable to open /dev/random: %s\n", strerror(errno)); return -1; } outbuf = malloc(obufsize); if (!outbuf) { fprintf(stdout, "Malloc failed on outbuf. Bad, bad, bad...\n"); exit(-1); } res = read(randdev, outbuf, obufsize); if (res <= 0) { fprintf(stdout, "WARNING: could not read from /dev/random: %s\n", strerror(errno)); return -1; } if (res != obufsize) { fprintf(stdout, "Could not read request %d bytes from /dev/random. Using only %d\n", obufsize, res); ibufsize = res; } close(randdev); outbuf = malloc(readduration); if (!outbuf) { fprintf(stdout, "Malloc failed on readbuf. Bad, bad, bad....\n"); exit(-1); } for (i = 0; i < total; i++) { int x; /* Set echo settings */ if (ioctl(whichzap, WCTDM_SET_ECHOTUNE, &echo_trys[i])) { fprintf(stdout, "Unable to set echo params: %s\n", strerror(errno)); return -1; } x = 1; if (ioctl(whichzap, ZT_SETLINEAR, &x)) { fprintf(stdout, "Unable to set channel to signed linear mode.\n"); return -1; } /* Take off hook */ x = ZT_OFFHOOK; if(ioctl(whichzap, ZT_HOOK, &x)) { fprintf(stdout, "Unable to set hook state.\n"); return -1; } /* write samples */ res = write(whichzap, outbuf, obufsize); if (res < 0) { fprintf(stdout, "Unable to write: %s\n", strerror(errno)); return -1; } if (res != obufsize) { fprintf(stdout, "Only could write %d of %d bytes.\n", res, obufsize); return -1; } res = read(whichzap, inbuf, ibufsize); if (res < 0) { fprintf(stdout, "Error in read: %s\n", strerror(errno)); return -1; } if (res != ibufsize) { fprintf(stdout, "Only could read %d of %d bytes.\n", res, ibufsize); if (res > 0) ibufsize = res; else { fprintf(stdout, "Cannot read from device\n"); return -1; } } res = process_readbuf(outbuf, obufsize, inbuf, ibufsize); /* Check to see if the echo values */ if (res < bestval) { bestval = res; bestindex = i; } } return 0; } int main (int argc , char **argv) { char zapdev[80] = ""; int i = 0; int fd; int res = 0; int configfd; if (argc != 2) { /* Show usage */ fputs(usage, stdout); return -1; } if (!strcasecmp(argv[1], "-s")) { for (i = 0;res != EOF; i++) { struct wctdm_echo_coefs mycoefs; char completezappath[56] = ""; int myzap,myacim,mycoef1,mycoef2,mycoef3,mycoef4,mycoef5,mycoef6,mycoef7,mycoef8; FILE *fp = NULL; fp = fopen(configfile, "r"); res = fscanf(fp, "%d=%d,%d,%d,%d,%d,%d,%d,%d,%d",&myzap,&myacim,&mycoef1, &mycoef2,&mycoef3,&mycoef4,&mycoef5,&mycoef6,&mycoef7, &mycoef8); if (res == EOF) { break; } /* Check to be sure conversion is done correctly */ if (OUT_OF_BOUNDS(myacim) || OUT_OF_BOUNDS(mycoef1)|| OUT_OF_BOUNDS(mycoef2)|| OUT_OF_BOUNDS(mycoef3)|| OUT_OF_BOUNDS(mycoef4)|| OUT_OF_BOUNDS(mycoef5)|| OUT_OF_BOUNDS(mycoef6)|| OUT_OF_BOUNDS(mycoef7)|| OUT_OF_BOUNDS(mycoef8)) { fprintf(stdout, "Bounds check error on inputs from %s:%d\n", configfile, i+1); return -1; } mycoefs.acim = myacim; mycoefs.coef1 = mycoef1; mycoefs.coef2 = mycoef2; mycoefs.coef3 = mycoef3; mycoefs.coef4 = mycoef4; mycoefs.coef5 = mycoef5; mycoefs.coef6 = mycoef6; mycoefs.coef7 = mycoef7; mycoefs.coef8 = mycoef8; snprintf(completezappath, sizeof(completezappath), "%s/%d", zappath, myzap); fd = open(completezappath, O_RDWR); if (fd < 0) { fprintf(stdout, "open error on %s: %s\n", completezappath, strerror(errno)); return -1; } if (ioctl(fd, WCTDM_SET_ECHOTUNE, &mycoefs)) { fprintf(stdout, "echotune: %s\n", strerror(errno)); return -1; } } return 0; } if (!strcasecmp(argv[1], "-i")) { configfd = open(configfile, O_CREAT|O_TRUNC|O_WRONLY); if (configfd < 0) { fprintf(stdout, "open: %s\n", strerror(errno)); return -1; } for (i = 0; i < 255; i++) { snprintf(zapdev, sizeof(zapdev), "%s/%d", zappath, i); fd = open(zapdev, O_RDWR); if (fd < 0) { fprintf(stdout, "open(%s): %s\n", zapdev, strerror(errno)); return -1; } res = echo_tune(fd); if (res > -1) { /* Do output to file */ int len = 0; static char output[255] = ""; snprintf(output, sizeof(output), "%d=%d,%d,%d,%d,%d,%d,%d,%d,%d", i, echo_trys[i].acim, echo_trys[i].coef1, echo_trys[i].coef2, echo_trys[i].coef3, echo_trys[i].coef4, echo_trys[i].coef5, echo_trys[i].coef6, echo_trys[i].coef7, echo_trys[i].coef8 ); len = strlen(output); res = write(configfd, output, strlen(output)); if (res != len) { fprintf(stdout, "Unable to write line \"%s\" to file.\n", output); return -1; } } } } return 0; }