xpp: README: hwid attribute of the xpd sysfs node
[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         time_t start_time = 0;
172
173         /* Parse the command line arguments */
174         while((opt = getopt(argc, argv, "b:s:t:r:v?h")) != -1) {
175                 switch(opt) {
176                 case 'h':
177                 case '?':
178                         usage(argv[0]);
179                         exit(1);
180                         break;
181                 case 'b':
182                         buff_disp = strtoul(optarg, NULL, 10);
183                         if (BLOCK_SIZE < buff_disp) {
184                                 buff_disp = BLOCK_SIZE;
185                         }
186                         oldstyle_cmdline = 0;
187                         break;
188                 case 'r':
189                         reportloops = strtoul(optarg, NULL, 10);
190                         oldstyle_cmdline = 0;
191                         break;
192                 case 's':
193                         skipcount = strtoul(optarg, NULL, 10);
194                         oldstyle_cmdline = 0;
195                         break;
196                 case 't':
197                         timeout = strtoul(optarg, NULL, 10);
198                         oldstyle_cmdline = 0;
199                         break;
200                 case 'v':
201                         verbose++;
202                         oldstyle_cmdline = 0;
203                         break;
204                 }
205         }
206
207         /* If no device was specified */
208         if(NULL == argv[optind]) {
209                 printf("You need to supply a dahdi device to test\n");
210                 usage(argv[0]);
211                 exit (1);
212         }
213
214         /* Get the dahdi device name */
215         if (argv[optind])
216                 device = argv[optind];
217
218         /* To maintain backward compatibility with previous versions process old style command line */
219         if (oldstyle_cmdline && argc > optind +1) {
220                 timeout = strtoul(argv[optind+1], NULL, 10);
221         }
222
223         fd = channel_open(device, &bs);
224         if (fd < 0)
225                 exit(1);
226         ioctl(fd, DAHDI_GETEVENT);
227
228         i = DAHDI_FLUSH_ALL;
229         if (ioctl(fd,DAHDI_FLUSH,&i) == -1) {
230                 perror("DAHDI_FLUSH");
231                 exit(255);
232         }
233
234         /* Mark time if program has a specified timeout */
235         if(0 < timeout){
236                 start_time = time(NULL);
237                 printf("Using Timeout of %d Seconds\n",timeout);
238         }
239
240         /* ********* MAIN TESTING LOOP ************ */
241         for(;;) {
242                 /* Prep the data and write it out to dahdi device */
243                 res = bs;
244                 for (x = 0; x < bs; x++) {
245                         outbuf[x] = c1++;
246                 }
247
248 write_again:
249                 res = write(fd,outbuf,bs);
250                 if (res != bs) {
251                         if (ELAST == errno) {
252                                 ioctl(fd, DAHDI_GETEVENT, &x);
253                                 if (event_count > 0)
254                                         printf("Event: %d\n", x);
255                                 ++event_count;
256                         } else {
257                                 printf("W: Res is %d: %s\n", res, strerror(errno));
258                         }
259                         goto write_again;
260                 }
261
262                 /* If this is the start of the test then skip a number of packets before test results */
263                 if (skipcount) {
264                         if (skipcount > 1) {
265                                 res = read(fd,inbuf,bs);
266                         }
267                         skipcount--;
268                         if (!skipcount) {
269                                 printf("Going for it...\n");
270                         }
271                         i = 1;
272                         ioctl(fd,DAHDI_BUFFER_EVENTS, &i);
273                         continue;
274                 }
275
276 read_again:
277                 res = read(fd, inbuf, bs);
278                 if (res < bs) {
279                         printf("R: Res is %d\n", res);
280                         ioctl(fd, DAHDI_GETEVENT, &x);
281                         printf("Event: %d\n", x);
282                         goto read_again;
283                 }
284                 /* If first time through, set byte that is used to test further bytes */
285                 if (!setup) {
286                         c = inbuf[0];
287                         setup++;
288                 }
289                 /* Test the packet read back for data pattern */
290                 loop_errorcount = 0;
291                 for (x = 0; x < bs; x++)  {
292                         /* if error */
293                         if (inbuf[x] != c) {
294                                 total_errorcount++;
295                                 loop_errorcount++;
296                                 if (oldstyle_cmdline) {
297                                         printf("(Error %ld): Unexpected result, %d != %d, %ld bytes since last error.\n", total_errorcount, inbuf[x],c, bytes);
298                                 } else {
299                                         if (1 <= verbose) {
300                                                 printf("Error %ld (loop %ld, offset %d, error %d): Unexpected result, Read: 0x%02x, Expected 0x%02x.\n",
301                                                         total_errorcount,
302                                                         currentloop,
303                                                         x,
304                                                         loop_errorcount,
305                                                         inbuf[x],
306                                                         c);
307                                         }
308                                         if (2 <= verbose) {
309                                                 show_error_context(inbuf, x, bs);
310                                         }
311                                 }
312                                 /* Reset the expected data to what was just read.  so test can resynch on skipped data */
313                                 c = inbuf[x];
314                                 bytes=0;  /* Reset the count from the last encountered error */
315                         }
316                         c++;
317                         bytes++;
318                 }
319                 /* If the user wants to see some of each buffer transaction */
320                 if (0 < buff_disp) {
321                         printf("Buffer Display %d (errors =%d)\nIN: ", buff_disp, loop_errorcount);
322                         print_packet(inbuf, 64);
323                         printf("OUT:");
324                         print_packet(outbuf, 64);
325                 }
326                 
327                 currentloop++;
328                 /* Update stats if the user has specified it */
329                 if (0 < reportloops && 0 == (currentloop % reportloops)) {
330                         printf("Status on loop %lu:  Total errors = %lu\n", currentloop, total_errorcount);
331                         
332                 }
333 #if 0
334                 printf("(%d) Wrote %d bytes\n", packets++, res);
335 #endif
336                 if(timeout && (time(NULL)-start_time) > timeout){
337                         printf("Timeout achieved Ending Program\n");
338                         printf("Test ran %ld loops of %d bytes/loop with %ld errors\n", currentloop, bs, total_errorcount);
339                         return total_errorcount;
340                 }
341         }
342         
343 }
344