dahdi_cfg: error()->perror() when sem_open fails.
[dahdi/tools.git] / fxotune.c
1 /* 
2  * fxotune.c -- A utility for tuning the various settings on the fxo
3  *              modules for the TDM400 cards.
4  *
5  * by Matthew Fredrickson <creslin@digium.com>
6  * 
7  * (C) 2004-2008 Digium, Inc.
8  */
9
10 /*
11  * See http://www.asterisk.org for more information about
12  * the Asterisk project. Please do not directly contact
13  * any of the maintainers of this project for assistance;
14  * the project provides a web site, mailing lists and IRC
15  * channels for your use.
16  *
17  * This program is free software, distributed under the terms of
18  * the GNU General Public License Version 2 as published by the
19  * Free Software Foundation. See the LICENSE file included with
20  * this program for more details.
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <string.h>
27 #include <sys/ioctl.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <math.h>
33 #include <sys/time.h>
34
35 #include <dahdi/user.h>
36 #include <dahdi/wctdm_user.h>
37
38 #include "dahdi_tools_version.h"
39 #include "fxotune.h"
40
41 #define TEST_DURATION 2000
42 #define BUFFER_LENGTH (2 * TEST_DURATION)
43 #define SKIP_SAMPLES 800
44 #define SINE_SAMPLES 8000
45
46 static float sintable[SINE_SAMPLES];
47
48 static const float amplitude = 16384.0;
49
50 static char *configfile = "/etc/fxotune.conf";
51
52 static int audio_dump_fd = -1;
53
54 static int printbest = 0;
55
56 #define MAX_RESULTS     (5)
57 struct result_catalog {
58         int     idx;
59         float   echo;
60         float   freqres;
61         struct wctdm_echo_coefs settings;
62 };
63
64 struct {
65         struct result_catalog results[MAX_RESULTS];
66         int numactive;
67 }       topresults;
68
69 static char *usage =
70 "Usage: fxotune [-v[vv] (-s | -i <options> | -d <options>)\n"
71 "\n"
72 "       -s : set previously calibrated echo settings\n"
73 "       -i : calibrate echo settings\n"
74 "               options : [<dialstring>] [-t <calibtype>]\n"
75 "               [-b <startdev>][-e <stopdev>]\n"
76 "               [-n <dialstring>][-l <delaytosilence>][-m <silencegoodfor>]\n"
77 "       -d : dump input and output waveforms to ./fxotune_dump.vals\n"
78 "               options : [-b <device>][-w <waveform>]\n"
79 "                  [-n <dialstring>][-l <delaytosilence>][-m <silencegoodfor>]\n"
80 "       -v : more output (-vv, -vvv also)\n"
81 "       -p : print the 5 best candidates for acim and coefficients settings\n"
82 "       -x : Perform sin/cos functions using table lookup\n"
83 "       -o <path> : Write the received raw 16-bit signed linear audio that is\n"
84 "                   used in processing to the file specified by <path>\n"
85 "       -c <config_file>\n"
86 "\n"
87 "               <calibtype>      - type of calibration\n"
88 "                                  (default 2, old method 1)\n"
89 "               <startdev>\n"
90 "               <stopdev>        - defines a range of devices to test\n"
91 "                                  (default: 1-252)\n"
92 "               <dialstring>     - string to dial to clear the line\n"
93 "                                  (default 5)\n"
94 "               <delaytosilence> - seconds to wait for line to clear (default 0)\n"
95 "               <silencegoodfor> - seconds before line will no longer be clear\n"
96 "                                  (default 18)\n"
97 "               <device>         - the device to perform waveform dump on\n"
98 "                                  (default 1)\n"
99 "               <waveform>       - -1 for multitone waveform, or frequency of\n"
100 "                                  single tone (default -1)\n"
101 "               <config_file>    - Alternative file to set from / calibrate to.\n"
102 "                                  (Default: /etc/fxotune.conf)\n"
103 ;
104
105
106 #define OUT_OF_BOUNDS(x) ((x) < 0 || (x) > 255)
107
108 struct silence_info{
109         char *dialstr;
110         /** fd of device we are working with */
111         int device; 
112         /** seconds we should wait after dialing the dialstring before we know for sure we'll have silence */
113         int initial_delay;
114         /** seconds after which a reset should occur */
115         int reset_after;
116         /** time of last reset */
117         struct timeval last_reset; 
118 };
119
120 static short outbuf[TEST_DURATION];
121 static int debug = 0;
122
123 static FILE *debugoutfile = NULL;
124
125 static int use_table = 0;
126
127 static int fxotune_read(int fd, void *buffer, int len)
128 {
129         int res;
130
131         res = read(fd, buffer, len);
132
133         if ((res > 0) && (audio_dump_fd != -1)) {
134                 res = write(audio_dump_fd, buffer, len);
135         }
136
137         return res;
138 }
139
140 /**
141  * Makes sure that the line is clear.
142  * Right now, we do this by relying on the user to specify how long after dialing the
143  * dialstring we can rely on the line being silent (before the telco complains about
144  * the user not hitting the next digit).
145  * 
146  * A more robust way to do this would be to actually measure the sound levels on the line,
147  * but that's a lot more complicated, and this should work.
148  * 
149  * @return 0 if succesful (no errors), 1 if unsuccesful
150  */
151 static int ensure_silence(struct silence_info *info)
152 {
153         struct timeval tv;
154         long int elapsedms;
155         int x = DAHDI_ONHOOK;
156         struct dahdi_dialoperation dop;
157
158         gettimeofday(&tv, NULL);
159         
160         if (info->last_reset.tv_sec == 0) {
161                 /* this is the first request, we will force it to run */
162                 elapsedms = -1;
163         } else {
164                 /* this is not the first request, we will compute elapsed time */
165                 elapsedms = ((tv.tv_sec - info->last_reset.tv_sec) * 1000L + (tv.tv_usec - info->last_reset.tv_usec) / 1000L);
166         }
167         if (debug > 4) {
168                 fprintf(stdout, "Reset line request received - elapsed ms = %li / reset after = %ld\n", elapsedms, info->reset_after * 1000L);
169         }
170
171         if (elapsedms > 0 && elapsedms < info->reset_after * 1000L)
172                 return 0;
173         
174         if (debug > 1){
175                 fprintf(stdout, "Resetting line\n");
176         }
177         
178         /* do a line reset */
179         /* prepare line for silence */
180         /* Do line hookstate reset */
181
182         if (ioctl(info->device, DAHDI_HOOK, &x)) {
183                 fprintf(stderr, "Unable to hang up fd %d\n", info->device);
184                 return -1;
185         }
186
187         sleep(2);
188         x = DAHDI_OFFHOOK;
189         if (ioctl(info->device, DAHDI_HOOK, &x)) {
190                 fprintf(stderr, "Cannot bring fd %d off hook\n", info->device);
191                 return -1;
192         }
193         sleep(2); /* Added to ensure that dial can actually takes place */
194
195         memset(&dop, 0, sizeof(dop));
196         dop.op = DAHDI_DIAL_OP_REPLACE;
197         dop.dialstr[0] = 'T';
198         dahdi_copy_string(dop.dialstr + 1, info->dialstr, sizeof(dop.dialstr));
199
200
201         if (ioctl(info->device, DAHDI_DIAL, &dop)) {
202                 fprintf(stderr, "Unable to dial!\n");
203                 return -1;
204         }
205         sleep(1); 
206         sleep(info->initial_delay);  
207         
208         
209         gettimeofday(&info->last_reset, NULL);
210         
211         
212         return 0;
213 }
214
215 /**
216  * Generates a tone of specified frequency.
217  * 
218  * @param hz the frequency of the tone to be generated
219  * @param idx the current sample
220  *              to begenerated.  For a normal waveform you need to increment
221  *              this every time you execute the function.
222  *
223  * @return 16bit slinear sample for the specified index
224  */
225 static short inline gentone(int hz, int idx)
226 {
227         return amplitude * sin((idx * 2.0 * M_PI * hz)/8000);
228 }
229
230 /* Using DTMF tones for now since they provide good mid band testing 
231  * while not being harmonics of each other */
232 static int freqs[] = {697, 770, 941, 1209, 1336, 1633};
233 static int freqcount = 6;
234
235 /**
236  * Generates a waveform of several frequencies.
237  * 
238  * @param idx the current sample
239  *              to begenerated.  For a normal waveform you need to increment
240  *              this every time you execute the function.
241  *
242  * @return 16bit slinear sample for the specified index
243  */
244 static short inline genwaveform(int idx)
245 {
246         int i = 0;
247         float response = (float)0;
248         for (i = 0; i < freqcount; i++){
249                 response += sin((idx * 2.0 * M_PI * freqs[i])/8000);
250         }
251         
252
253         return amplitude * response / freqcount;
254 }
255
256
257 /**
258  *  Calculates the RMS of the waveform buffer of samples in 16bit slinear format.
259  *  prebuf the buffer of either shorts or floats
260  *  bufsize the number of elements in the prebuf buffer (not the number of bytes!)
261  *  short_format 1 if prebuf points to an array of shorts, 0 if it points to an array of floats
262  *  
263  *  Formula for RMS (http://en.wikipedia.org/wiki/Root_mean_square): 
264  *  
265  *  Xrms = sqrt(1/N Sum(x1^2, x2^2, ..., xn^2))
266  *  
267  *  Note:  this isn't really a power calculation - but it gives a good measure of the level of the response
268  *  
269  *  @param prebuf the buffer containing the values to compute
270  *  @param bufsize the size of the buffer
271  *  @param short_format 1 if prebuf contains short values, 0 if it contains float values
272  */
273 static float power_of(void *prebuf, int bufsize, int short_format)
274 {
275         float sum_of_squares = 0;
276         int numsamples = 0;
277         float finalanswer = 0;
278         short *sbuf = (short*)prebuf;
279         float *fbuf = (float*)prebuf;
280         int i = 0;
281
282         if (short_format) {
283                 /* idiot proof checks */
284                 if (bufsize <= 0)
285                         return -1;
286
287                 numsamples = bufsize; /* Got rid of divide by 2 - the bufsize parameter should give the number of samples (that's what it does for the float computation, and it should do it here as well) */
288
289                 for (i = 0; i < numsamples; i++) {
290                         sum_of_squares += ((float)sbuf[i] * (float)sbuf[i]);
291                 }
292         } else {
293                 /* Version for float inputs */
294                 for (i = 0; i < bufsize; i++) {
295                         sum_of_squares += (fbuf[i] * fbuf[i]);
296                 }
297         }
298
299         finalanswer = sum_of_squares/(float)bufsize; /* need to divide by the number of elements in the sample for RMS calc */
300
301         if (finalanswer < 0) {
302                 fprintf(stderr, "Error: Final answer negative number %f\n", finalanswer);
303                 return -3;
304         }
305
306         return sqrtf(finalanswer);
307 }
308
309 /* 
310  * In an effort to eliminate as much as possible the effect of outside noise, we use principles
311  * from the Fourier Transform to attempt to calculate the return loss of our signal for each setting.
312  *
313  * To begin, we send our output signal out on the line.  We then receive back the reflected
314  * response.  In the Fourier Transform, each evenly distributed frequency within the window
315  * is correlated (multiplied against, then the resulting samples are added together) with
316  * the real (cos) and imaginary (sin) portions of that frequency base to detect that frequency.
317  * 
318  * Instead of doing a complete Fourier Transform, we solve the transform for only our signal
319  * by multiplying the received signal by the real and imaginary portions of our reference
320  * signal.  This then gives us the real and imaginary values that we can use to calculate
321  * the return loss of the sinusoids that we sent out on the line.  This is done by finding
322  * the magnitude (think polar form) of the vector resulting from the real and imaginary
323  * portions calculated above.
324  *
325  * This essentially filters out any other noise which maybe present on the line which is outside
326  * the frequencies used in our test multi-tone.
327  */
328
329 void init_sinetable(void)
330 {
331         int i;
332         if (debug) {
333                 fprintf(stdout, "Using sine tables with %d samples\n", SINE_SAMPLES);
334         }
335         for (i = 0; i < SINE_SAMPLES; i++) {
336                 sintable[i] = sin(((float)i * 2.0 * M_PI )/(float)(SINE_SAMPLES));
337         }
338 }
339
340 /* Sine and cosine table lookup to use periodicity of the calculations being done */
341 float sin_tbl(int arg, int num_per_period)
342 {
343         arg = arg % num_per_period;
344
345         arg = (arg * SINE_SAMPLES)/num_per_period;
346
347         return sintable[arg];
348 }
349
350 float cos_tbl(int arg, int num_per_period)
351 {
352         arg = arg  % num_per_period;
353
354         arg = (arg * SINE_SAMPLES)/num_per_period;
355
356         arg = (arg + SINE_SAMPLES/4) % SINE_SAMPLES;  /* Pi/2 adjustment */
357
358         return sintable[arg];
359 }
360
361
362 static float db_loss(float measured, float reference)
363 {
364         return 20 * (logf(measured/reference)/logf(10));
365 }
366
367 static void one_point_dft(const short *inbuf, int len, int frequency, float *real, float *imaginary)
368 {
369         float myreal = 0, myimag = 0;
370         int i;
371
372         for (i = 0; i < len; i++) {
373                 if (use_table) {
374                         myreal += (float) inbuf[i] * cos_tbl(i*frequency, 8000);
375                         myimag += (float) inbuf[i] * sin_tbl(i*frequency, 8000);
376                 } else {
377                         myreal += (float) inbuf[i] * cos((i * 2.0 * M_PI * frequency)/8000);
378                         myimag += (float) inbuf[i] * sin((i * 2.0 * M_PI * frequency)/8000);
379                 }
380         }
381
382         myimag *= -1;
383
384         *real = myreal / (float) len;
385         *imaginary = myimag / (float) len;
386 }
387
388
389 static float calc_magnitude(short *inbuf, int insamps)
390 {
391         float real, imaginary, magnitude;
392         float totalmagnitude = 0;
393         int i;
394
395         for (i = 0; i < freqcount; i++) {
396                 one_point_dft(inbuf, insamps, freqs[i], &real, &imaginary);
397                 magnitude = sqrtf((real * real) + (imaginary * imaginary));
398                 totalmagnitude += magnitude;
399         }
400
401         return totalmagnitude;
402 }
403
404
405 /**
406  *  dumps input and output buffer contents for the echo test - used to see exactly what's going on
407  */
408 static int maptone(int whichdahdi, int freq, char *dialstr, int delayuntilsilence)
409 {
410         int i = 0;
411         int res = 0, x = 0;
412         struct dahdi_bufferinfo bi;
413         short inbuf[TEST_DURATION]; /* changed from BUFFER_LENGTH - this buffer is for short values, so it should be allocated using the length of the test */
414         FILE *outfile = NULL;
415         int leadin = 50;
416         int trailout = 100;
417         struct silence_info sinfo;
418         float power_result;
419         float power_waveform;
420         float echo;
421
422         outfile = fopen("fxotune_dump.vals", "w");
423         if (!outfile) {
424                 fprintf(stdout, "Cannot create fxotune_dump.vals\n");
425                 return -1;
426         }
427
428         x = 1;
429         if (ioctl(whichdahdi, DAHDI_SETLINEAR, &x)) {
430                 fprintf(stderr, "Unable to set channel to signed linear mode.\n");
431                 return -1;
432         }
433
434         memset(&bi, 0, sizeof(bi));
435         if (ioctl(whichdahdi, DAHDI_GET_BUFINFO, &bi)) {
436                 fprintf(stderr, "Unable to get buffer information!\n");
437                 return -1;
438         }
439         bi.numbufs = 2;
440         bi.bufsize = TEST_DURATION; /* KD - changed from BUFFER_LENGTH; */
441         bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
442         bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
443         if (ioctl(whichdahdi, DAHDI_SET_BUFINFO, &bi)) {
444                 fprintf(stderr, "Unable to set buffer information!\n");
445                 return -1;
446         }
447
448         /* Fill the output buffers */
449         for (i = 0; i < leadin; i++)
450                 outbuf[i] = 0;
451         for (; i < TEST_DURATION - trailout; i++){
452                 outbuf[i] = freq > 0 ? gentone(freq, i) : genwaveform(i); /* if frequency is negative, use a multi-part waveform instead of a single frequency */
453         }
454         for (; i < TEST_DURATION; i++)
455                 outbuf[i] = 0;
456
457         /* Make sure the line is clear */
458         memset(&sinfo, 0, sizeof(sinfo));
459         sinfo.device = whichdahdi;
460         sinfo.dialstr = dialstr;
461         sinfo.initial_delay = delayuntilsilence;
462         sinfo.reset_after = 4; /* doesn't matter - we are only running one test */
463         
464         if (ensure_silence(&sinfo)){
465                 fprintf(stderr, "Unable to get a clear outside line\n");
466                 return -1;
467         }
468
469         /* Flush buffers */
470         x = DAHDI_FLUSH_READ | DAHDI_FLUSH_WRITE | DAHDI_FLUSH_EVENT;
471         if (ioctl(whichdahdi, DAHDI_FLUSH, &x)) {
472                 fprintf(stderr, "Unable to flush I/O: %s\n", strerror(errno));
473                 return -1;
474         }
475
476         /* send data out on line */
477         res = write(whichdahdi, outbuf, BUFFER_LENGTH); /* we are sending a TEST_DURATION length array of shorts (which are 2 bytes each) */
478         if (res != BUFFER_LENGTH) { 
479                 fprintf(stderr, "Could not write all data to line\n");
480                 return -1;
481         }
482
483 retry:
484                 /* read return response */
485         res = fxotune_read(whichdahdi, inbuf, BUFFER_LENGTH);
486         if (res != BUFFER_LENGTH) {
487                 int dummy;
488
489                 ioctl(whichdahdi, DAHDI_GETEVENT, &dummy);
490                 goto retry;
491         }
492
493         /* write content of output buffer to debug file */
494         power_result = power_of(inbuf, TEST_DURATION, 1);
495         power_waveform = power_of(outbuf, TEST_DURATION, 1);
496         echo = power_result/power_waveform;
497         
498         fprintf(outfile, "Buffers, freq=%d, outpower=%0.0f, echo=%0.4f\n", freq, power_result, echo);
499         fprintf(outfile, "Sample, Input (received from the line), Output (sent to the line)\n");
500         for (i = 0; i < TEST_DURATION; i++){
501                 fprintf(outfile, "%d, %d, %d\n", 
502                         i,
503                         inbuf[i],
504                         outbuf[i]
505                 );
506         }
507
508         fclose(outfile);
509         
510         fprintf(stdout, "echo ratio = %0.4f (%0.1f / %0.1f)\n", echo, power_result, power_waveform);
511         
512         return 0;
513 }
514
515
516 /**
517  *  Initialize the data store for storing off best calculated results
518  */
519 static void init_topresults(void)
520 {
521         topresults.numactive = 0;
522 }
523
524
525 /**
526  *  If this is a best result candidate, store in the top results data store
527  *              This is dependent on being the lowest echo value
528  *
529  *  @param tbleoffset - The offset into the echo_trys table used
530  *  @param setting - Pointer to the settings used to achieve the fgiven value
531  *  @param echo - The calculated echo return value (in dB)
532  *  @param echo - The calculated magnitude of the response
533  */
534 static void set_topresults(int tbloffset, struct wctdm_echo_coefs *setting, float echo, float freqres)
535 {
536         int place;
537         int idx;
538
539         for ( place = 0; place < MAX_RESULTS && place < topresults.numactive; place++) {
540                 if (echo < topresults.results[place].echo) {
541                         break;
542                 }
543         }
544
545         if (place < MAX_RESULTS) {
546                 /*  move results to the bottom */
547                 for (idx = topresults.numactive-2; idx >= place; idx--) {
548                         topresults.results[idx+1] = topresults.results[idx];
549                 }
550                 topresults.results[place].idx = tbloffset;
551                 topresults.results[place].settings = *setting;
552                 topresults.results[place].echo = echo;
553                 topresults.results[place].freqres = freqres;
554                 if (MAX_RESULTS > topresults.numactive) {
555                         topresults.numactive++;
556                 }
557         }
558 }
559
560
561 /**
562  *  Prints the top results stored to stdout
563  *
564  *  @param header - Text that goes in the header of the response
565  */
566 static void print_topresults(char * header)
567 {
568         int item;
569
570         fprintf(stdout, "Top %d results for %s\n", topresults.numactive, header);
571         for (item = 0; item < topresults.numactive; item++) {
572                 fprintf(stdout, "Res #%d: index=%d, %3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d: magnitude = %0.0f, echo = %0.4f dB\n",
573                                 item+1, topresults.results[item].idx, topresults.results[item].settings.acim,
574                                 topresults.results[item].settings.coef1, topresults.results[item].settings.coef2,
575                                 topresults.results[item].settings.coef3, topresults.results[item].settings.coef4,
576                                 topresults.results[item].settings.coef5, topresults.results[item].settings.coef6,
577                                 topresults.results[item].settings.coef7, topresults.results[item].settings.coef8,
578                                 topresults.results[item].freqres, topresults.results[item].echo);
579                 
580         }
581 }
582
583
584 /**
585  * Perform calibration type 2 on the specified device
586  * 
587  * Determine optimum echo coefficients for the specified device
588  * 
589  * New tuning strategy.  If we have a number that we can dial that will result in silence from the
590  * switch, the tune will be *much* faster (we don't have to keep hanging up and dialing a digit, etc...)
591  * The downside is that the user needs to actually find a 'no tone' phone number at their CO's switch - but for
592  * really fixing echo problems, this is what it takes.
593  *
594  * Also, for the purposes of optimizing settings, if we pick a single frequency and test with that,
595  * we can try a whole bunch of impedence/echo coefficients.  This should give better results than trying
596  * a bunch of frequencies, and we can always do a a frequency sweep to pick between the best 3 or 4
597  * impedence/coefficients configurations.
598  *   
599  * Note:  It may be possible to take this even further and do some pertubation analysis on the echo coefficients
600  *               themselves (maybe use the 72 entry sweep to find some settings that are close to working well, then
601  *               deviate the coefficients a bit to see if we can improve things).  A better way to do this would be to
602  *               use the optimization strategy from silabs.  For reference, here is an application note that describes
603  *               the echo coefficients (and acim values):
604  *               
605  *               http://www.silabs.com/Support%20Documents/TechnicalDocs/an84.pdf
606  *
607  *               See Table 13 in this document for a breakdown of acim values by region.
608  *
609  *               http://www.silabs.com/Support%20Documents/TechnicalDocs/si3050-18-19.pdf
610  *               
611  */
612 static int acim_tune2(int whichdahdi, int freq, char *dialstr, int delayuntilsilence, int silencegoodfor, struct wctdm_echo_coefs *coefs_out)
613 {
614         int i = 0;
615         int res = 0, x = 0;
616         int lowesttry = -1;
617         float lowesttryresult = 999999999999.0;
618         float lowestecho = 999999999999.0;
619         struct dahdi_bufferinfo bi;
620         short inbuf[TEST_DURATION * 2];
621         struct silence_info sinfo;
622         int echo_trys_size = 72;
623         int trys = 0;
624         float waveform_power;
625         float freq_result;
626         float echo;
627
628         init_topresults();
629
630         if (debug && !debugoutfile) {
631                 if (!(debugoutfile = fopen("fxotune.vals", "w"))) {
632                         fprintf(stdout, "Cannot create fxotune.vals\n");
633                         return -1;
634                 }
635         }
636
637         /* Set echo settings */
638         if (ioctl(whichdahdi, WCTDM_SET_ECHOTUNE, &echo_trys[0])) {
639                 fprintf(stderr, "Unable to set impedance on fd %d\n", whichdahdi);
640                 return -1;
641         }
642
643         x = 1;
644         if (ioctl(whichdahdi, DAHDI_SETLINEAR, &x)) {
645                 fprintf(stderr, "Unable to set channel to signed linear mode.\n");
646                 return -1;
647         }
648
649         memset(&bi, 0, sizeof(bi));
650         if (ioctl(whichdahdi, DAHDI_GET_BUFINFO, &bi)) {
651                 fprintf(stderr, "Unable to get buffer information!\n");
652                 return -1;
653         }
654         bi.numbufs = 2;
655         bi.bufsize = BUFFER_LENGTH;
656         bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
657         bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
658         if (ioctl(whichdahdi, DAHDI_SET_BUFINFO, &bi)) {
659                 fprintf(stderr, "Unable to set buffer information!\n");
660                 return -1;
661         }
662         x = DAHDI_OFFHOOK;
663         if (ioctl(whichdahdi, DAHDI_HOOK, &x)) {
664                 fprintf(stderr, "Cannot bring fd %d off hook", whichdahdi);
665                 return -1;
666         }
667
668
669         /* Set up silence settings */
670         memset(&sinfo, 0, sizeof(sinfo));
671         sinfo.device = whichdahdi;
672         sinfo.dialstr = dialstr;
673         sinfo.initial_delay = delayuntilsilence;
674         sinfo.reset_after = silencegoodfor;
675
676         /* Fill the output buffers */
677         for (i = 0; i < TEST_DURATION; i++)
678                 outbuf[i] = freq > 0 ? gentone(freq, i) : genwaveform(i); /* if freq is negative, use a multi-frequency waveform */
679         
680         /* compute power of input (so we can later compute echo levels relative to input) */
681         waveform_power = calc_magnitude(outbuf, TEST_DURATION);
682
683         /* sweep through the various coefficient settings and see how our responses look */
684
685         for (trys = 0; trys < echo_trys_size; trys++){
686                 
687                 /* ensure silence on the line */
688                 if (ensure_silence(&sinfo)){
689                         fprintf(stderr, "Unable to get a clear outside line\n");
690                         return -1;
691                 }
692                 
693                 if (ioctl(whichdahdi, WCTDM_SET_ECHOTUNE, &echo_trys[trys])) {
694                         fprintf(stderr, "Unable to set echo coefficients on fd %d\n", whichdahdi);
695                         return -1;
696                 }
697
698                 /* Flush buffers */
699                 x = DAHDI_FLUSH_READ | DAHDI_FLUSH_WRITE | DAHDI_FLUSH_EVENT;
700                 if (ioctl(whichdahdi, DAHDI_FLUSH, &x)) {
701                         fprintf(stderr, "Unable to flush I/O: %s\n", strerror(errno));
702                         return -1;
703                 }
704
705                 /* send data out on line */
706                 res = write(whichdahdi, outbuf, BUFFER_LENGTH);
707                 if (res != BUFFER_LENGTH) {
708                         fprintf(stderr, "Could not write all data to line\n");
709                         return -1;
710                 }
711
712 retry:
713                 /* read return response */
714                 res = fxotune_read(whichdahdi, inbuf, BUFFER_LENGTH * 2);
715                 if (res != BUFFER_LENGTH * 2) {
716                         int dummy;
717
718                         ioctl(whichdahdi, DAHDI_GETEVENT, &dummy);
719                         goto retry;
720                 }
721
722                 freq_result = calc_magnitude(inbuf, TEST_DURATION * 2);
723                 echo = db_loss(freq_result, waveform_power);
724                 
725 #if 0
726                 if (debug > 0)
727                         fprintf(stdout, "%3d,%d,%d,%d,%d,%d,%d,%d,%d: magnitude = %0.0f, echo = %0.4f dB\n", 
728                                         echo_trys[trys].acim, echo_trys[trys].coef1, echo_trys[trys].coef2,
729                                         echo_trys[trys].coef3, echo_trys[trys].coef4, echo_trys[trys].coef5,
730                                         echo_trys[trys].coef6, echo_trys[trys].coef7, echo_trys[trys].coef8,
731                                         freq_result, echo);
732 #endif
733
734                 if (freq_result < lowesttryresult){
735                         lowesttry = trys;
736                         lowesttryresult = freq_result;
737                         lowestecho = echo;
738                 }
739                 if (debug) {
740                         char result[256];
741                         snprintf(result, sizeof(result), "%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%f,%f", 
742                                                 echo_trys[trys].acim, 
743                                                 echo_trys[trys].coef1, 
744                                                 echo_trys[trys].coef2, 
745                                                 echo_trys[trys].coef3, 
746                                                 echo_trys[trys].coef4, 
747                                                 echo_trys[trys].coef5, 
748                                                 echo_trys[trys].coef6, 
749                                                 echo_trys[trys].coef7, 
750                                                 echo_trys[trys].coef8, 
751                                                 freq_result,
752                                                 echo
753                                         );
754                         
755                         fprintf(debugoutfile, "%s\n", result);
756                         fprintf(stdout, "%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d: magnitude = %0.0f, echo = %0.4f dB\n",
757                                         echo_trys[trys].acim, echo_trys[trys].coef1, echo_trys[trys].coef2,
758                                         echo_trys[trys].coef3, echo_trys[trys].coef4, echo_trys[trys].coef5,
759                                         echo_trys[trys].coef6, echo_trys[trys].coef7, echo_trys[trys].coef8,
760                                         freq_result, echo);
761                 }
762
763                 if (printbest) {
764                         set_topresults(trys, &echo_trys[trys], echo, freq_result);
765                 }
766         }
767
768         if (debug > 0)
769                 fprintf(stdout, "Config with lowest response = %d, magnitude = %0.0f, echo = %0.4f dB\n", lowesttry, lowesttryresult, lowestecho);
770
771         memcpy(coefs_out, &echo_trys[lowesttry], sizeof(struct wctdm_echo_coefs));
772         if (printbest) {
773                 print_topresults("Acim2_tune Test");
774         }
775
776         return 0;
777 }
778
779 /**
780  *  Perform calibration type 1 on the specified device.  Only tunes the line impedance.  Look for best response range 
781  */
782 static int acim_tune(int whichdahdi, char *dialstr, int delayuntilsilence, int silencegoodfor, struct wctdm_echo_coefs *coefs_out)
783 {
784         int i = 0, freq = 0, acim = 0;
785         int res = 0, x = 0;
786         struct dahdi_bufferinfo bi;
787         struct wctdm_echo_coefs coefs;
788         short inbuf[TEST_DURATION]; /* changed from BUFFER_LENGTH - this buffer is for short values, so it should be allocated using the length of the test */
789         int lowest = 0;
790         FILE *outfile = NULL;
791         float acim_results[16];
792         struct silence_info sinfo;
793
794         if (debug) {
795                 outfile = fopen("fxotune.vals", "w");
796                 if (!outfile) {
797                         fprintf(stdout, "Cannot create fxotune.vals\n");
798                         return -1;
799                 }
800         }
801
802         /* Set up silence settings */
803         memset(&sinfo, 0, sizeof(sinfo));
804         sinfo.device = whichdahdi;
805         sinfo.dialstr = dialstr;
806         sinfo.initial_delay = delayuntilsilence;
807         sinfo.reset_after = silencegoodfor;
808         
809         /* Set echo settings */
810         memset(&coefs, 0, sizeof(coefs));
811         if (ioctl(whichdahdi, WCTDM_SET_ECHOTUNE, &coefs)) {
812                 fprintf(stdout, "Skipping non-TDM / non-FXO\n");
813                 return -1;
814         }
815
816         x = 1;
817         if (ioctl(whichdahdi, DAHDI_SETLINEAR, &x)) {
818                 fprintf(stderr, "Unable to set channel to signed linear mode.\n");
819                 return -1;
820         }
821
822         memset(&bi, 0, sizeof(bi));
823         if (ioctl(whichdahdi, DAHDI_GET_BUFINFO, &bi)) {
824                 fprintf(stderr, "Unable to get buffer information!\n");
825                 return -1;
826         }
827         bi.numbufs = 2;
828         bi.bufsize = BUFFER_LENGTH;
829         bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
830         bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
831         if (ioctl(whichdahdi, DAHDI_SET_BUFINFO, &bi)) {
832                 fprintf(stderr, "Unable to set buffer information!\n");
833                 return -1;
834         }
835
836         for (acim = 0; acim < 16; acim++) {
837                 float freq_results[15];
838
839                 coefs.acim = acim;
840                 if (ioctl(whichdahdi, WCTDM_SET_ECHOTUNE, &coefs)) {
841                         fprintf(stderr, "Unable to set impedance on fd %d\n", whichdahdi);
842                         return -1;
843                 }
844
845                 for (freq = 200; freq <=3000; freq+=200) {
846                         /* Fill the output buffers */
847                         for (i = 0; i < TEST_DURATION; i++)
848                                 outbuf[i] = gentone(freq, i);
849
850                         /* Make sure line is ready for next test iteration */
851                         if (ensure_silence(&sinfo)){
852                                 fprintf(stderr, "Unable to get a clear line\n");
853                                 return -1;
854                         }
855                         
856
857                         /* Flush buffers */
858                         x = DAHDI_FLUSH_READ | DAHDI_FLUSH_WRITE | DAHDI_FLUSH_EVENT;
859                         if (ioctl(whichdahdi, DAHDI_FLUSH, &x)) {
860                                 fprintf(stderr, "Unable to flush I/O: %s\n", strerror(errno));
861                                 return -1;
862                         }
863         
864                         /* send data out on line */
865                         res = write(whichdahdi, outbuf, BUFFER_LENGTH);
866                         if (res != BUFFER_LENGTH) {
867                                 fprintf(stderr, "Could not write all data to line\n");
868                                 return -1;
869                         }
870
871                         /* read return response */
872 retry:
873                         /* read return response */
874                         res = fxotune_read(whichdahdi, inbuf, BUFFER_LENGTH);
875                         if (res != BUFFER_LENGTH) {
876                                 int dummy;
877         
878                                 ioctl(whichdahdi, DAHDI_GETEVENT, &dummy);
879                                 goto retry;
880                         }
881
882                         /* calculate power of response */
883                         
884                         freq_results[(freq/200)-1] = power_of(inbuf+SKIP_SAMPLES, TEST_DURATION-SKIP_SAMPLES, 1); /* changed from inbuf+SKIP_BYTES, BUFFER_LENGTH-SKIP_BYTES, 1 */
885                         if (debug) fprintf(outfile, "%d,%d,%f\n", acim, freq, freq_results[(freq/200)-1]);
886                 }
887                 acim_results[acim] = power_of(freq_results, 15, 0);
888         }
889
890         if (debug) {
891                 for (i = 0; i < 16; i++)
892                         fprintf(outfile, "acim_results[%d] = %f\n", i, acim_results[i]);
893         }
894         /* Find out what the "best" impedance is for the line */
895         lowest = 0;
896         for (i = 0; i < 16; i++) {
897                 if (acim_results[i] < acim_results[lowest]) {
898                         lowest = i;
899                 }
900         }
901
902         coefs_out->acim = lowest;
903         coefs_out->coef1 = 0;
904         coefs_out->coef2 = 0;
905         coefs_out->coef3 = 0;
906         coefs_out->coef4 = 0;
907         coefs_out->coef5 = 0;
908         coefs_out->coef6 = 0;
909         coefs_out->coef7 = 0;
910         coefs_out->coef8 = 0;
911         
912         return 0;
913 }
914
915 static int channel_is_fxo(int channo)
916 {
917         int res = 0;
918         int fd;
919         const char *CTL_DEV = "/dev/dahdi/ctl";
920         struct dahdi_params params;
921
922         fd = open(CTL_DEV, O_RDWR, 0600);
923         if (-1 == fd) {
924                 fprintf(stderr, "Failed to open %s: %s\n",
925                         CTL_DEV, strerror(errno));
926                 return -1;
927         }
928         params.channo = channo;
929         if (ioctl(fd, DAHDI_GET_PARAMS, &params)) {
930                 fprintf(stderr,
931                         "%d is not a valid channel number.\n", channo);
932                 res = -1;
933         } else if (0 == (__DAHDI_SIG_FXS & params.sigcap)) {
934                 fprintf(stderr,
935                         "Channel %d is not an FXO port.\n", channo);
936                 res = -1;
937         } else if (0 == params.sigtype) {
938                 fprintf(stderr,
939                         "Cannot run on unconfigured channel %d. Please run dahdi_cfg to configure channels before running fxotune.\n",
940                         channo);
941                 res = -1;
942         }
943         close(fd);
944         return res;
945 }
946
947 static int channel_open(int channo)
948 {
949         int     fd;
950         const char *DEVICE = "/dev/dahdi/channel";
951
952         if (channo > 0) {
953                 if (channel_is_fxo(channo))
954                         return -1;
955
956                 fd = open(DEVICE, O_RDWR, 0600);
957                 if (fd < 0) {
958                         perror(DEVICE);
959                         return -1;
960                 }
961
962                 if (ioctl(fd, DAHDI_SPECIFY, &channo) < 0) {
963                         perror("DADHI_SPECIFY ioctl failed");
964                         close(fd);
965                         fd = -1;
966                 }
967         } else {
968                 fprintf(stderr,
969                         "Specified channel is not a valid channel number");
970                 fd = -1;
971         }
972         return fd;
973 }
974
975 /**
976  * Reads echo register settings from the configuration file and pushes them into
977  * the appropriate devices
978  * 
979  * @param configfilename the path of the file that the calibration results should be written to
980  * 
981  * @return 0 if successful, !0 otherwise
982  */     
983 static int do_set(char *configfilename, int dev_range, int startdev, int stopdev)
984 {
985         FILE *fp = NULL;
986         int res = 0;
987         int fd = 0;
988                 
989         fp = fopen(configfile, "r");
990         
991     if (!fp) {
992             fprintf(stdout, "Cannot open %s!\n",configfile);
993             return -1;
994     }
995
996         
997         while (res != EOF) {
998                 struct wctdm_echo_coefs mycoefs;
999                 char completedahdipath[56] = "";
1000                 int mydahdi,myacim,mycoef1,mycoef2,mycoef3,mycoef4,mycoef5,mycoef6,mycoef7,mycoef8;
1001
1002
1003                 res = fscanf(fp, "%d=%d,%d,%d,%d,%d,%d,%d,%d,%d",&mydahdi,&myacim,&mycoef1,
1004                                 &mycoef2,&mycoef3,&mycoef4,&mycoef5,&mycoef6,&mycoef7,
1005                                 &mycoef8);
1006
1007                 if (res == EOF) {
1008                         break;
1009                 }
1010                 if (dev_range && (mydahdi < startdev || mydahdi > stopdev))
1011                         continue;
1012
1013                 /* Check to be sure conversion is done correctly */
1014                 if (OUT_OF_BOUNDS(myacim) || OUT_OF_BOUNDS(mycoef1)||
1015                         OUT_OF_BOUNDS(mycoef2)|| OUT_OF_BOUNDS(mycoef3)||
1016                         OUT_OF_BOUNDS(mycoef4)|| OUT_OF_BOUNDS(mycoef5)||
1017                         OUT_OF_BOUNDS(mycoef6)|| OUT_OF_BOUNDS(mycoef7)|| OUT_OF_BOUNDS(mycoef8)) {
1018
1019                         fprintf(stdout, "Bounds check error on inputs from %s:%d\n", configfile, mydahdi);
1020                         return -1;
1021                 }
1022
1023                 mycoefs.acim = myacim;
1024                 mycoefs.coef1 = mycoef1;
1025                 mycoefs.coef2 = mycoef2;
1026                 mycoefs.coef3 = mycoef3;
1027                 mycoefs.coef4 = mycoef4;
1028                 mycoefs.coef5 = mycoef5;
1029                 mycoefs.coef6 = mycoef6;
1030                 mycoefs.coef7 = mycoef7;
1031                 mycoefs.coef8 = mycoef8;
1032         
1033                 if (debug >= 2)
1034                         printf("fxotune: set channel %d\n", mydahdi);
1035                 fd = channel_open(mydahdi);
1036                 if (fd < 0) {
1037                         return -1;
1038                 }
1039
1040                 if (ioctl(fd, WCTDM_SET_ECHOTUNE, &mycoefs)) {
1041                         fprintf(stdout, "%s: %s\n", completedahdipath, strerror(errno));
1042                         return -1;
1043                 }
1044
1045                 close(fd);
1046         }
1047
1048         fclose(fp);
1049
1050         if (debug)
1051                 fprintf(stdout, "fxotune: successfully set echo coeffecients on FXO modules\n");
1052         return 0;       
1053 }
1054
1055 /**
1056  * Output waveform information from a single test
1057  * 
1058  * Clears the line, then sends a single waveform (multi-tone, or single tone), and listens
1059  * for the response on the line.  Output is written to fxotune_dump.vals
1060  * 
1061  * @param startdev the device to test
1062  * @param dialstr the string that should be dialed to clear the dialtone from the line
1063  * @param delayuntilsilence the number of seconds to wait after dialing dialstr before starting the test
1064  * @param silencegoodfor the number of seconds that the test can run before having to reset the line again
1065  *                      (this is basically the amount of time it takes before the 'if you'd like to make a call...' message
1066  *                      kicks in after you dial dialstr.  This test is so short that the value is pretty much ignored.
1067  * @param waveformtype the type of waveform to use - -1 = multi-tone waveform, otherwise the specified value
1068  *                      is used as the frequency of a single tone.  A value of 0 will output silence.
1069  */
1070 static int do_dump(int startdev, char* dialstr, int delayuntilsilence, int silencegoodfor, int waveformtype)
1071 {
1072         int res = 0;
1073         int fd;
1074         char dahdidev[80] = "";
1075         
1076         int dahdimodule = startdev;
1077         fd = channel_open(dahdimodule);
1078         if (fd < 0) {
1079                 return -1;
1080         }
1081
1082         fprintf(stdout, "Dumping module %s\n", dahdidev);
1083         res = maptone(fd, waveformtype, dialstr, delayuntilsilence); 
1084
1085         close(fd);
1086
1087         if (res) {
1088                 fprintf(stdout, "Failure!\n");
1089                 return res;
1090         } else {
1091                 fprintf(stdout, "Done!\n");
1092                 return 0;
1093         }
1094
1095 }       
1096
1097 /**
1098  * Performs calibration on all specified devices
1099  * 
1100  * @param startdev the first device to check
1101  * @param enddev the last device to check
1102  * @param calibtype the type of calibration to perform.  1=old style (loops through individual frequencies
1103  *                      doesn't optimize echo coefficients.  2=new style (uses multi-tone and optimizes echo coefficients
1104  *                      and acim setting)
1105  * @param configfilename the path of the file that the calibration results should be written to
1106  * @param dialstr the string that should be dialed to clear the dialtone from the line
1107  * @param delayuntilsilence the number of seconds to wait after dialing dialstr before starting the test
1108  * @param silencegoodfor the number of seconds that the test can run before having to reset the line again
1109  *                      (this is basically the amount of time it takes before the 'if you'd like to make a call...' message
1110  *                      kicks in after you dial dialstr
1111  * 
1112  * @return 0 if successful, -1 for serious error such as device not available , > 0 indicates the number of channels
1113  */     
1114 static int do_calibrate(int startdev, int enddev, int calibtype, char* configfilename, char* dialstr, int delayuntilsilence, int silencegoodfor)
1115 {
1116         int problems = 0;
1117         int res = 0;
1118         int configfd, fd;
1119         int devno = 0;
1120         struct wctdm_echo_coefs coefs;
1121         
1122         configfd = open(configfile, O_CREAT|O_TRUNC|O_WRONLY, 0666);
1123
1124         if (configfd < 0) {
1125                 fprintf(stderr, "Cannot generate config file %s: open: %s\n", configfile, strerror(errno));
1126                 return -1;
1127         }
1128
1129         for (devno = startdev; devno <= enddev; devno++) {
1130                 fd = channel_open(devno);
1131                 if (fd < 0) {
1132                         continue;
1133                 }
1134
1135                 fprintf(stdout, "Tuning module %d\n", devno);
1136                 
1137                 if (1 == calibtype)
1138                         res = acim_tune(fd, dialstr, delayuntilsilence, silencegoodfor, &coefs);
1139                 else
1140                         res = acim_tune2(fd, -1, dialstr, delayuntilsilence, silencegoodfor, &coefs);
1141
1142                 close(fd);
1143                 
1144                 if (res) {
1145                         fprintf(stdout, "Failure!\n");
1146                         problems++;
1147                 } else {
1148                         fprintf(stdout, "Done!\n");
1149                 }
1150
1151                 if (res == 0) {
1152                         
1153                 /* Do output to file */
1154                         int len = 0;
1155                         static char output[255] = "";
1156
1157                         snprintf(output, sizeof(output), "%d=%d,%d,%d,%d,%d,%d,%d,%d,%d\n", 
1158                                 devno,
1159                                 coefs.acim, 
1160                                 coefs.coef1, 
1161                                 coefs.coef2, 
1162                                 coefs.coef3, 
1163                                 coefs.coef4, 
1164                                 coefs.coef5, 
1165                                 coefs.coef6, 
1166                                 coefs.coef7, 
1167                                 coefs.coef8
1168                         );
1169
1170                         if (debug)
1171                                 fprintf(stdout, "Found best echo coefficients: %s\n", output);
1172
1173                         len = strlen(output);
1174                         res = write(configfd, output, strlen(output));
1175                         if (res != len) {
1176                                 fprintf(stdout, "Unable to write line \"%s\" to file.\n", output);
1177                                 return -1;
1178                         }
1179                 }
1180         }
1181
1182         close(configfd);
1183         
1184         if (problems)
1185                 fprintf(stdout, "Unable to tune %d devices, even though those devices are present\n", problems);
1186         
1187         return problems;
1188 }       
1189         
1190 int main(int argc , char **argv)
1191 {
1192         int startdev = 1; /* -b */
1193         int stopdev = 252; /* -e */
1194         int dev_range = 0; /* false */
1195         int calibtype = 2; /* -t */
1196         int waveformtype = -1; /* -w multi-tone by default.  If > 0, single tone of specified frequency */
1197         int delaytosilence = 0; /* -l */
1198         int silencegoodfor = 18; /* -m */
1199         char* dialstr = "5"; /* -n */
1200         int res = 0;
1201         int doset = 0; /* -s */
1202         int docalibrate = 0; /* -i <dialstr> */
1203         int dodump = 0; /* -d */
1204         int i = 0;
1205         int moreargs;
1206         
1207         for (i = 1; i < argc; i++){
1208                 if (!(argv[i][0] == '-' || argv[i][0] == '/') || (strlen(argv[i]) <= 1)){
1209                         fprintf(stdout, "Unknown option : %s\n", argv[i]);
1210                         /* Show usage */
1211                         fputs(usage, stdout);
1212                         return -1;
1213                 }
1214
1215                 moreargs = (i < argc - 1);
1216                 
1217                 switch(argv[i][1]){
1218                         case 's':
1219                                 doset=1;
1220                                 continue;
1221                         case 'i':
1222                                 docalibrate = 1;
1223                                 if (moreargs){ /* we need to check for a value after 'i' for backwards compatability with command line options of old fxotune */
1224                                         if (argv[i+1][0] != '-' && argv[i+1][0] != '/')
1225                                                 dialstr = argv[++i];
1226                                 }
1227                                 continue;
1228                         case 'c':
1229                                 configfile = moreargs ? argv[++i] : configfile;
1230                                 continue;
1231                         case 'd':
1232                                 dodump = 1;
1233                                 continue;
1234                         case 'b':
1235                                 startdev = moreargs ? atoi(argv[++i]) : startdev;
1236                                 dev_range = 1;
1237                                 break;
1238                         case 'e':
1239                                 stopdev = moreargs ? atoi(argv[++i]) : stopdev;
1240                                 dev_range = 1;
1241                                 break;
1242                         case 't':
1243                                 calibtype = moreargs ? atoi(argv[++i]) : calibtype;
1244                                 break;
1245                         case 'w':
1246                                 waveformtype = moreargs ? atoi(argv[++i]) : waveformtype;
1247                                 break;
1248                         case 'l':
1249                                 delaytosilence = moreargs ? atoi(argv[++i]) : delaytosilence;
1250                                 break;
1251                         case 'm':
1252                                 silencegoodfor = moreargs ? atoi(argv[++i]) : silencegoodfor;
1253                                 break;
1254                         case 'n':
1255                                 dialstr = moreargs ? argv[++i] : dialstr;
1256                                 break;
1257                         case 'p':
1258                                 printbest++;
1259                                 break;
1260                         case 'x':
1261                                 use_table = 1;
1262                                 break;
1263                         case 'v':
1264                                 debug = strlen(argv[i])-1;
1265                                 break;
1266                         case 'o':
1267                                 if (moreargs) {
1268                                         audio_dump_fd = open(argv[++i], O_WRONLY|O_CREAT|O_TRUNC, 0666);
1269                                         if (audio_dump_fd == -1) {
1270                                                 fprintf(stdout, "Unable to open file %s: %s\n", argv[i], strerror(errno));
1271                                                 return -1;
1272                                         }
1273                                         break;
1274                                 } else {
1275                                         fprintf(stdout, "No path supplied to -o option!\n");
1276                                         return -1;
1277                                 }
1278                         default:
1279                                 fprintf(stdout, "Unknown option : %s\n", argv[i]);
1280                                 /* Show usage */
1281                                 fputs(usage, stdout);
1282                                 return -1;
1283                                 
1284                 }
1285         }
1286         
1287         if (debug > 3){
1288                 fprintf(stdout, "Running with parameters:\n");
1289                 fprintf(stdout, "\tdoset=%d\n", doset); 
1290                 fprintf(stdout, "\tdocalibrate=%d\n", docalibrate);     
1291                 fprintf(stdout, "\tdodump=%d\n", dodump);       
1292                 fprintf(stdout, "\tprint best settings=%d\n", printbest);
1293                 fprintf(stdout, "\tstartdev=%d\n", startdev);
1294                 fprintf(stdout, "\tstopdev=%d\n", stopdev);     
1295                 fprintf(stdout, "\tcalibtype=%d\n", calibtype); 
1296                 fprintf(stdout, "\twaveformtype=%d\n", waveformtype);   
1297                 fprintf(stdout, "\tdelaytosilence=%d\n", delaytosilence);       
1298                 fprintf(stdout, "\tsilencegoodfor=%d\n", silencegoodfor);       
1299                 fprintf(stdout, "\tdialstr=%s\n", dialstr);     
1300                 fprintf(stdout, "\tdebug=%d\n", debug); 
1301         }
1302
1303         if(use_table) {
1304                 init_sinetable();
1305         }
1306         
1307         if (docalibrate){
1308                 res = do_calibrate(startdev, stopdev, calibtype, configfile, dialstr, delaytosilence, silencegoodfor);
1309                 if (!res)
1310                         return do_set(configfile, dev_range, startdev, stopdev);
1311                 else
1312                         return -1;
1313         }
1314
1315         if (doset)
1316                 return do_set(configfile, dev_range, startdev, stopdev);
1317                                 
1318         if (dodump){
1319                 res = do_dump(startdev, dialstr, delaytosilence, silencegoodfor, waveformtype);
1320                 if (!res)
1321                         return 0;
1322                 else
1323                         return -1;
1324         }
1325
1326         fputs(usage, stdout);
1327         return -1;
1328 }