From 7048b429d602e171634a418e2a367edae9efb74a Mon Sep 17 00:00:00 2001 From: mattf Date: Wed, 2 Feb 2005 18:01:08 +0000 Subject: New impedance tuning algorithms. git-svn-id: http://svn.digium.com/svn/zaptel/trunk@577 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- fxotune.c | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 220 insertions(+), 18 deletions(-) (limited to 'fxotune.c') diff --git a/fxotune.c b/fxotune.c index 6b29159..1f04df5 100755 --- a/fxotune.c +++ b/fxotune.c @@ -20,6 +20,8 @@ #include #include #include +#include + #ifdef STANDALONE_ZAPATA #include "zaptel.h" #else @@ -28,8 +30,11 @@ #include "wctdm.h" #include "fxotune.h" -#define TESTDURATION 64 /* 64 samples of test */ -#define BUFFER_LENGTH 128 /* 128 sample buffers */ +#define TEST_DURATION 4000 /* 4000 samples (or 500 ms) of test */ +#define BUFFER_LENGTH 8000 /* 4000 sample buffers */ +#define SKIP_BYTES 1600 + +#define PI 3.14 static char *zappath = "/dev/zap"; static char *configfile = "/etc/fxotune.conf"; @@ -41,9 +46,11 @@ static char *usage = #define OUT_OF_BOUNDS(x) ((x) < 0 || (x) > 255) -static short outbuf[TESTDURATION]; +static short outbuf[TEST_DURATION]; static int debug = 0; + +#if 0 int process_readbuf(short *ibuf) { int sum=0; @@ -53,12 +60,76 @@ int process_readbuf(short *ibuf) } return sum; } +#endif + +/* Generates a tone of hz frequency. Index is the current sample + * to begenerated. For a normal waveform you need to increment + * this every time you execute the function. + * Returns a 16bit slinear sample. */ +short gentone(int hz, int index) +{ + return sinf(index * 2 * PI * hz/8000); +} -int fill_outputdata(void) +/* Returns the power of the buffer of samples in 16bit slinear format. + * power function = (sum of squares) - (square of sums). + * + * TODO: make the function stateless so that you can have some sort of + * progressive power calculation on the line */ +float power_of(void *prebuf, int bufsize, int short_format) { + float sum_of_squares = 0, square_of_sums = 0; + int numsamples = 0; + float finalanswer = 0; + short *sbuf = (short*)prebuf; + float *fbuf = (float*)prebuf; + int i = 0; + + if (short_format) { + /* idiot proof checks */ + if (bufsize <= 0) + return -1; + + if (bufsize % 2 != 0) + return -2; + + numsamples = bufsize / 2; + + for (i = 0; i < numsamples; i++) { + sum_of_squares += ((float)sbuf[i] * (float)sbuf[i])/(float)32768; + square_of_sums += (float)sbuf[i]/(float)32768; + } + } else { + /* Version for float inputs */ + for (i = 0; i < bufsize; i++) { + sum_of_squares += (fbuf[i] * fbuf[i]); + square_of_sums += fbuf[i]; + } + } + + square_of_sums *= square_of_sums; /* sums ^ 2 */ + + finalanswer = sum_of_squares - square_of_sums; + + if (finalanswer < 0) + return -3; + + return sqrtf(finalanswer); +} + +#if 0 +int fill_outputdata(int freq) +{ + int i = 0; + + for (i = 0; i < TESTDURATIION; i++) + outbuf[i] = gentone(freq, i); + + + int randdev; int cursize = 0; - int needlen = TESTDURATION * 2; + int needlen = TEST_DURATION * 2; int res; fprintf(stdout, "Getting random impulse data\n"); @@ -78,13 +149,15 @@ int fill_outputdata(void) needlen -= res; } - fprintf(stdout, "Cool, we filled the random data buffer\n"); + fprintf(stdout, "Succesfully filled the random data buffer\n"); close(randdev); return 0; } +#endif +#if 0 /* Returns index in echocan table with the lowest power pulse readback * -1 means the device is not an FXO module or fails */ static int echo_tune(int whichzap, const char *dialstr) @@ -164,14 +237,14 @@ static int echo_tune(int whichzap, const char *dialstr) } /* write samples */ - res = write(whichzap, outbuf, TESTDURATION * 2); + res = write(whichzap, outbuf, TEST_DURATION * 2); if (res < 0) { fprintf(stdout, "Unable to write: %s\n", strerror(errno)); return -1; } - if (res != TESTDURATION * 2) { - fprintf(stdout, "Only could write %d of %d bytes.\n", res, TESTDURATION * 2); + if (res != TEST_DURATION * 2) { + fprintf(stdout, "Only could write %d of %d bytes.\n", res, TEST_DURATION * 2); return -1; } @@ -210,6 +283,136 @@ static int echo_tune(int whichzap, const char *dialstr) return 0; } +#endif + +/* Tune the line impedance. Look for best response range */ +int acim_tune(int whichzap, char *dialstr) +{ + int i = 0, freq = 0, acim = 0; + int res = 0, x = 0; + struct zt_bufferinfo bi; + struct zt_dialoperation dop; + struct wctdm_echo_coefs coefs; + short inbuf[BUFFER_LENGTH]; + int lowest = 0; + float acim_results[16]; + + /* Set echo settings */ + memset(&coefs, 0, sizeof(coefs)); + if (ioctl(whichzap, WCTDM_SET_ECHOTUNE, &coefs)) { + fprintf(stdout, "Skipping non-TDM / non-FXO\n"); + return -1; + } + + x = 1; + if (ioctl(whichzap, ZT_SETLINEAR, &x)) { + fprintf(stderr, "Unable to set channel to signed linear mode.\n"); + return -1; + } + + memset(&bi, 0, sizeof(bi)); + if (ioctl(whichzap, ZT_GET_BUFINFO, &bi)) { + fprintf(stderr, "Unable to get buffer information!\n"); + return -1; + } + bi.numbufs = 2; + bi.bufsize = BUFFER_LENGTH; + bi.txbufpolicy = ZT_POLICY_IMMEDIATE; + bi.rxbufpolicy = ZT_POLICY_IMMEDIATE; + if (ioctl(whichzap, ZT_SET_BUFINFO, &bi)) { + fprintf(stderr, "Unable to set buffer information!\n"); + return -1; + } + x = ZT_OFFHOOK; + if (ioctl(whichzap, ZT_HOOK, &x)) { + fprintf(stderr, "Cannot bring fd %d off hook", whichzap); + return -1; + } + + for (acim = 0; acim < 16; acim++) { + float freq_results[15]; + int needtoreset = 0; + + coefs.acim = acim; + if (ioctl(whichzap, WCTDM_SET_ECHOTUNE, &coefs)) { + fprintf(stderr, "Unable to set impedance on fd %d\n", whichzap); + return -1; + } + + for (freq = 200; freq <=3000; freq+=200, needtoreset++) { + /* Fill the output buffers */ + for (i = 0; i < TEST_DURATION; i++) + outbuf[i] = gentone(freq, i); + + /* Prepare line for data */ + if (needtoreset > 8) { + /* Do line hookstate reset */ + x = ZT_ONHOOK; + + if (ioctl(whichzap, ZT_HOOK, &x)) { + fprintf(stderr, "Unable to hang up fd %d\n", whichzap); + return -1; + } + + sleep(2); + x = ZT_OFFHOOK; + if (ioctl(whichzap, ZT_HOOK, &x)) { + fprintf(stderr, "Cannot bring fd %d off hook", whichzap); + return -1; + } + + memset(&dop, 0, sizeof(dop)); + dop.op = ZT_DIAL_OP_REPLACE; + dop.dialstr[0] = 'T'; + strncpy(dop.dialstr + 1, dialstr, sizeof(dop.dialstr) - 1); + printf("Dialing...\n"); + if (ioctl(whichzap, ZT_DIAL, &dop)) { + fprintf(stderr, "Unable to dial!\n"); + return -1; + } + sleep(2); + + needtoreset = 0; + } + + /* Flush buffers */ + x = ZT_FLUSH_READ | ZT_FLUSH_WRITE | ZT_FLUSH_EVENT; + if (ioctl(whichzap, ZT_FLUSH, &x)) { + fprintf(stderr, "Unable to flush I/O: %s\n", strerror(errno)); + return -1; + } + + /* send data out on line */ + res = write(whichzap, &outbuf, BUFFER_LENGTH); + if (res != BUFFER_LENGTH) { + fprintf(stderr, "Could not write all data to line\n"); + return -1; + } + + /* read return response */ + res = read(whichzap, inbuf, BUFFER_LENGTH); + if (res != BUFFER_LENGTH) { + fprintf(stderr, "Could not fill input buffer\n"); + return -1; + } + + /* calculate power of response */ + + freq_results[(freq/200)-1] = power_of(inbuf+SKIP_BYTES, BUFFER_LENGTH-SKIP_BYTES, 1); + } + acim_results[i] = power_of(freq_results, 16, 0); + } + + /* Find out what the "best" impedance is for the line */ + lowest = 1; + for (i = 0; i < 16; i++) { + if (acim_results[i] < acim_results[lowest]) { + lowest = i; + } + } + + return lowest; +} int main (int argc , char **argv) { @@ -299,11 +502,6 @@ int main (int argc , char **argv) return -1; } - if (fill_outputdata()) { - fprintf(stdout, "Error in generating outputdata... dieing\n"); - return -1; - } - for (i = 0; i < 252; i++) { snprintf(zapdev, sizeof(zapdev), "%s/%d", zappath, i+1); @@ -314,18 +512,22 @@ int main (int argc , char **argv) continue; } - res = echo_tune(fd, argv[2]); + res = acim_tune(fd, argv[2]); close(fd); if (res > -1) { /* Do output to file */ int len = 0; static char output[255] = ""; +#if 0 snprintf(output, sizeof(output), "%d=%d,%d,%d,%d,%d,%d,%d,%d,%d\n", i+1, - echo_trys[res].acim, echo_trys[res].coef1, echo_trys[res].coef2, - echo_trys[res].coef3, echo_trys[res].coef4, echo_trys[res].coef5, - echo_trys[res].coef6, echo_trys[res].coef7, echo_trys[res].coef8 ); + 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 ); +#endif + snprintf(output, sizeof(output), "%d=%d,%d,%d,%d,%d,%d,%d,%d,%d\n", i+1, res, + 0, 0, 0, 0, 0, 0, 0, 0); len = strlen(output); res = write(configfd, output, strlen(output)); if (res != len) { -- cgit v1.2.3