summaryrefslogtreecommitdiff
path: root/fxotune.c
diff options
context:
space:
mode:
authormattf <mattf@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2005-02-02 18:01:08 +0000
committermattf <mattf@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2005-02-02 18:01:08 +0000
commit7048b429d602e171634a418e2a367edae9efb74a (patch)
treef413befa57872be844178d805ed48d33a142023e /fxotune.c
parent7d566fd52849468db440f0c7c113832a25d37d96 (diff)
New impedance tuning algorithms.
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@577 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'fxotune.c')
-rwxr-xr-xfxotune.c238
1 files changed, 220 insertions, 18 deletions
diff --git a/fxotune.c b/fxotune.c
index 6b29159..1f04df5 100755
--- a/fxotune.c
+++ b/fxotune.c
@@ -20,6 +20,8 @@
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
+#include <math.h>
+
#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) {