automake: add basic libtool support
[dahdi/tools.git] / patlooptest.c
1 /*
2  * Written by Mark Spencer <markster@digium.com>
3  * Based on previous works, designs, and architectures conceived and
4  * written by Jim Dixon <jim@lambdatel.com>.
5  *
6  * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
7  * Copyright (C) 2001-2008 Digium, Inc.
8  *
9  * All rights reserved.
10  *
11  * Primary Author: Mark Spencer <markster@digium.com>
12  * Radio Support by Jim Dixon <jim@lambdatel.com>
13  */
14
15 /*
16  * See http://www.asterisk.org for more information about
17  * the Asterisk project. Please do not directly contact
18  * any of the maintainers of this project for assistance;
19  * the project provides a web site, mailing lists and IRC
20  * channels for your use.
21  *
22  * This program is free software, distributed under the terms of
23  * the GNU General Public License Version 2 as published by the
24  * Free Software Foundation. See the LICENSE file included with
25  * this program for more details.
26  */
27
28 /*
29  *      This test sends a set of incrementing byte values out the specified
30  * dadhi device.  The device is then read back and the read back characters
31  * are verified that they increment as well.
32  *      If there is a break in the incrementing pattern, an error is flagged 
33  * and the comparison starts at the last value read. 
34  */
35
36 #include <stdio.h>
37 #include <fcntl.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <stdio.h>
41 #include <sys/ioctl.h>
42 #include <sys/stat.h>
43 #include <unistd.h>
44 #include <stdlib.h>
45 #include <time.h>
46
47 #include <dahdi/user.h>
48 #include "dahdi_tools_version.h"
49
50 #define BLOCK_SIZE      2039
51 #define DEVICE  "/dev/dahdi/channel"
52
53 #define CONTEXT_SIZE    7
54 /* Prints a set of bytes in hex format */
55 static void print_packet(unsigned char *buf, int len)
56 {
57         int x;
58         printf("{ ");
59         for (x=0;x<len;x++)
60                 printf("%02x ",buf[x]);
61         printf("}\n");
62 }
63
64 /* Shows data immediately before and after the specified byte to provide context for an error */
65 static void show_error_context(unsigned char *buf, int offset, int bufsize)
66 {
67         int low;
68         int total = CONTEXT_SIZE;
69
70         if (offset >= bufsize || 0 >= bufsize || 0 > offset ) {
71                 return;
72         }
73         
74         low = offset - (CONTEXT_SIZE-1)/2;
75         if (0 > low) {
76                 total += low;
77                 low = 0;
78         }
79         if (low + total > bufsize) {
80                 total = bufsize - low;
81         }
82         buf += low;
83         printf("Offset %d  ", low);
84         print_packet(buf, total);
85         return;
86 }
87
88 /* Shows how the program can be invoked */
89 static void usage(const char * progname)
90 {
91         printf("%s: Pattern loop test\n", progname);
92         printf("Usage:  %s <dahdi device> [-t <secs>] [-r <count>] [-b <count>] [-vh?] \n", progname);
93         printf("\t-? - Print this usage summary\n");
94         printf("\t-t <secs> - # of seconds for the test to run\n");
95         printf("\t-r <count> - # of test loops to run before a summary is printed\n");
96         printf("\t-s <count> - # of writes to skip before testing for results\n");
97         printf("\t-v - Verbosity (repetitive v's add to the verbosity level e.g. -vvvv)\n");
98         printf("\t-b <# buffer bytes> - # of bytes to display from buffers on each pass\n");
99         printf("\n\t Also accepts old style usage:\n\t  %s <device name> [<timeout in secs>]\n", progname);
100 }
101
102 int channel_open(const char *name, int *bs)
103 {
104         int     channo, fd;
105         struct  dahdi_params tp;
106         struct  stat filestat;
107
108         /* stat file, if character device, open it */
109         channo = strtoul(name, NULL, 10);
110         fd = stat(name, &filestat);
111         if (!fd && S_ISCHR(filestat.st_mode)) {
112                 fd = open(name, O_RDWR, 0600);
113                 if (fd < 0) {
114                         perror(name);
115                         return -1;
116                 }
117         /* try out the dahdi_specify interface */
118         } else if (channo > 0) {
119                 fd = open(DEVICE, O_RDWR, 0600);
120                 if (fd < 0) {
121                         perror(DEVICE);
122                         return -1;
123                 }
124                 if (ioctl(fd, DAHDI_SPECIFY, &channo) < 0) {
125                         perror("DAHDI_SPECIFY ioctl failed");
126                         return -1;
127                 }
128         /* die */
129         } else {
130                 fprintf(stderr, "Specified channel is not a valid character "
131                         "device or channel number");
132                 return -1;
133         }
134
135         if (ioctl(fd, DAHDI_SET_BLOCKSIZE, bs) < 0) {
136                 perror("SET_BLOCKSIZE");
137                 return -1;
138         }
139
140         if (ioctl(fd, DAHDI_GET_PARAMS, &tp)) {
141                 fprintf(stderr, "Unable to get channel parameters\n");
142                 return -1;
143         }
144
145         return fd;
146 }
147
148 int main(int argc, char *argv[])
149 {
150         int fd;
151         int res, x;
152         int i;
153         int bs = BLOCK_SIZE;
154         int skipcount = 10;
155         unsigned char c=0,c1=0;
156         unsigned char inbuf[BLOCK_SIZE];
157         unsigned char outbuf[BLOCK_SIZE];
158         int setup=0;
159         unsigned long bytes=0;
160         int timeout=0;
161         int loop_errorcount;
162         int reportloops = 0;
163         int buff_disp = 0; 
164         unsigned long currentloop = 0;
165         unsigned long total_errorcount = 0;
166         int verbose = 0; 
167         char * device;
168         int opt;
169         int oldstyle_cmdline = 1;
170         unsigned int event_count = 0;
171
172         /* Parse the command line arguments */
173         while((opt = getopt(argc, argv, "b:s:t:r:v?h")) != -1) {
174                 switch(opt) {
175                 case 'h':
176                 case '?':
177                         usage(argv[0]);
178                         exit(1);
179                         break;
180                 case 'b':
181                         buff_disp = strtoul(optarg, NULL, 10);
182                         if (BLOCK_SIZE < buff_disp) {
183                                 buff_disp = BLOCK_SIZE;
184                         }
185                         oldstyle_cmdline = 0;
186                         break;
187                 case 'r':
188                         reportloops = strtoul(optarg, NULL, 10);
189                         oldstyle_cmdline = 0;
190                         break;
191                 case 's':
192                         skipcount = strtoul(optarg, NULL, 10);
193                         oldstyle_cmdline = 0;
194                         break;
195                 case 't':
196                         timeout = strtoul(optarg, NULL, 10);
197                         oldstyle_cmdline = 0;
198                         break;
199                 case 'v':
200                         verbose++;
201                         oldstyle_cmdline = 0;
202                         break;
203                 }
204         }
205
206         /* If no device was specified */
207         if(NULL == argv[optind]) {
208                 printf("You need to supply a dahdi device to test\n");
209                 usage(argv[0]);
210                 exit (1);
211         }
212
213         /* Get the dahdi device name */
214         if (argv[optind])
215                 device = argv[optind];
216
217         /* To maintain backward compatibility with previous versions process old style command line */
218         if (oldstyle_cmdline && argc > optind +1) {
219                 timeout = strtoul(argv[optind+1], NULL, 10);
220         }
221         
222         time_t start_time = 0;
223
224         fd = channel_open(device, &bs);
225         if (fd < 0)
226                 exit(1);
227         ioctl(fd, DAHDI_GETEVENT);
228
229         i = DAHDI_FLUSH_ALL;
230         if (ioctl(fd,DAHDI_FLUSH,&i) == -1) {
231                 perror("DAHDI_FLUSH");
232                 exit(255);
233         }
234
235         /* Mark time if program has a specified timeout */
236         if(0 < timeout){
237                 start_time = time(NULL);
238                 printf("Using Timeout of %d Seconds\n",timeout);
239         }
240
241         /* ********* MAIN TESTING LOOP ************ */
242         for(;;) {
243                 /* Prep the data and write it out to dahdi device */
244                 res = bs;
245                 for (x = 0; x < bs; x++) {
246                         outbuf[x] = c1++;
247                 }
248
249 write_again:
250                 res = write(fd,outbuf,bs);
251                 if (res != bs) {
252                         if (ELAST == errno) {
253                                 ioctl(fd, DAHDI_GETEVENT, &x);
254                                 if (event_count > 0)
255                                         printf("Event: %d\n", x);
256                                 ++event_count;
257                         } else {
258                                 printf("W: Res is %d: %s\n", res, strerror(errno));
259                         }
260                         goto write_again;
261                 }
262
263                 /* If this is the start of the test then skip a number of packets before test results */
264                 if (skipcount) {
265                         if (skipcount > 1) {
266                                 res = read(fd,inbuf,bs);
267                         }
268                         skipcount--;
269                         if (!skipcount) {
270                                 printf("Going for it...\n");
271                         }
272                         i = 1;
273                         ioctl(fd,DAHDI_BUFFER_EVENTS, &i);
274                         continue;
275                 }
276
277 read_again:
278                 res = read(fd, inbuf, bs);
279                 if (res < bs) {
280                         printf("R: Res is %d\n", res);
281                         ioctl(fd, DAHDI_GETEVENT, &x);
282                         printf("Event: %d\n", x);
283                         goto read_again;
284                 }
285                 /* If first time through, set byte that is used to test further bytes */
286                 if (!setup) {
287                         c = inbuf[0];
288                         setup++;
289                 }
290                 /* Test the packet read back for data pattern */
291                 loop_errorcount = 0;
292                 for (x = 0; x < bs; x++)  {
293                         /* if error */
294                         if (inbuf[x] != c) {
295                                 total_errorcount++;
296                                 loop_errorcount++;
297                                 if (oldstyle_cmdline) {
298                                         printf("(Error %ld): Unexpected result, %d != %d, %ld bytes since last error.\n", total_errorcount, inbuf[x],c, bytes);
299                                 } else {
300                                         if (1 <= verbose) {
301                                                 printf("Error %ld (loop %ld, offset %d, error %d): Unexpected result, Read: 0x%02x, Expected 0x%02x.\n",
302                                                         total_errorcount,
303                                                         currentloop,
304                                                         x,
305                                                         loop_errorcount,
306                                                         inbuf[x],
307                                                         c);
308                                         }
309                                         if (2 <= verbose) {
310                                                 show_error_context(inbuf, x, bs);
311                                         }
312                                 }
313                                 /* Reset the expected data to what was just read.  so test can resynch on skipped data */
314                                 c = inbuf[x];
315                                 bytes=0;  /* Reset the count from the last encountered error */
316                         }
317                         c++;
318                         bytes++;
319                 }
320                 /* If the user wants to see some of each buffer transaction */
321                 if (0 < buff_disp) {
322                         printf("Buffer Display %d (errors =%d)\nIN: ", buff_disp, loop_errorcount);
323                         print_packet(inbuf, 64);
324                         printf("OUT:");
325                         print_packet(outbuf, 64);
326                 }
327                 
328                 currentloop++;
329                 /* Update stats if the user has specified it */
330                 if (0 < reportloops && 0 == (currentloop % reportloops)) {
331                         printf("Status on loop %lu:  Total errors = %lu\n", currentloop, total_errorcount);
332                         
333                 }
334 #if 0
335                 printf("(%d) Wrote %d bytes\n", packets++, res);
336 #endif
337                 if(timeout && (time(NULL)-start_time) > timeout){
338                         printf("Timeout achieved Ending Program\n");
339                         printf("Test ran %ld loops of %d bytes/loop with %ld errors\n", currentloop, bs, total_errorcount);
340                         return total_errorcount;
341                 }
342         }
343         
344 }
345