summaryrefslogtreecommitdiff
path: root/fxotune.c
diff options
context:
space:
mode:
authormattf <mattf@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2005-01-08 00:05:24 +0000
committermattf <mattf@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2005-01-08 00:05:24 +0000
commitf59bc698cc7f139b93a9c51eb65f342a789e725f (patch)
tree24921b81b0417c112be5db999a4fd2de0c0041cd /fxotune.c
parent3ac20515e24dba5119fa2d5b06157d81d84e9cc3 (diff)
More TDM card echo API modifications. Making the fxotune program automatically
find the correct coefficients for the module. Lots of neat stuff. git-svn-id: http://svn.digium.com/svn/zaptel/trunk@531 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'fxotune.c')
-rwxr-xr-xfxotune.c262
1 files changed, 242 insertions, 20 deletions
diff --git a/fxotune.c b/fxotune.c
index 6bdaeba..a11ba90 100755
--- a/fxotune.c
+++ b/fxotune.c
@@ -1,3 +1,16 @@
+/*
+ * 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 <stdio.h>
#include <stdlib.h>
#include <errno.h>
@@ -5,42 +18,251 @@
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <unistd.h>
#include <fcntl.h>
#include <linux/zaptel.h>
#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;
-
- if (argc < 4) {
- fprintf(stdout, "Usage:\n");
- fprintf(stdout, "%s [zap device] echocan [0-7]\n", argv[0]);
- exit(1);
+ int res = 0;
+ int configfd;
+
+ if (argc != 2) {
+ /* Show usage */
+ fputs(usage, stdout);
+ return -1;
}
- strncpy(zapdev, argv[1], sizeof(zapdev));
+ 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;
+ }
- fd = open(zapdev, O_RDWR);
- if (fd < 0) {
- fprintf(stderr, "open: %s\n", strerror(errno));
- exit(1);
+ if (ioctl(fd, WCTDM_SET_ECHOTUNE, &mycoefs)) {
+ fprintf(stdout, "echotune: %s\n", strerror(errno));
+ return -1;
+ }
+ }
+
+ return 0;
}
- if (!strcasecmp(argv[2], "echocan")) {
- int modeno = atoi(argv[3]);
+ if (!strcasecmp(argv[1], "-i")) {
+ configfd = open(configfile, O_CREAT|O_TRUNC|O_WRONLY);
- if (modeno < 0 || modeno > 7) {
- fprintf(stdout, "Echo canceller coefficient settings must be between 0 and 7.\n");
- exit(1);
+ if (configfd < 0) {
+ fprintf(stdout, "open: %s\n", strerror(errno));
+ return -1;
}
- if (ioctl(fd, WCTDM_SET_ECHOTUNE, &modeno)) {
- fprintf(stdout, "echotune: %s\n", strerror(errno));
- exit(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;
+ }
+ }
}
- exit(0);
}
- exit(0);
+
+ return 0;
}