2010-08-18 21:49:24 +08:00
|
|
|
/*
|
|
|
|
* Written by Mark Spencer <markster@digium.com>
|
|
|
|
* Based on previous works, designs, and architectures conceived and
|
|
|
|
* written by Jim Dixon <jim@lambdatel.com>.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2001 Jim Dixon / Zapata Telephony.
|
|
|
|
* Copyright (C) 2001-2008 Digium, Inc.
|
|
|
|
*
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Primary Author: Mark Spencer <markster@digium.com>
|
|
|
|
* Radio Support by Jim Dixon <jim@lambdatel.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* See http://www.asterisk.org for more information about
|
|
|
|
* the Asterisk project. Please do not directly contact
|
|
|
|
* any of the maintainers of this project for assistance;
|
|
|
|
* the project provides a web site, mailing lists and IRC
|
|
|
|
* channels for your use.
|
|
|
|
*
|
|
|
|
* This program is free software, distributed under the terms of
|
|
|
|
* the GNU General Public License Version 2 as published by the
|
|
|
|
* Free Software Foundation. See the LICENSE file included with
|
|
|
|
* this program for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This test sends a set of incrementing byte values out the specified
|
|
|
|
* dadhi device. The device is then read back and the read back characters
|
|
|
|
* are verified that they increment as well.
|
|
|
|
* If there is a break in the incrementing pattern, an error is flagged
|
|
|
|
* and the comparison starts at the last value read.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <sys/ioctl.h>
|
2011-06-08 03:44:34 +08:00
|
|
|
#include <sys/stat.h>
|
2010-08-18 21:49:24 +08:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
#include <dahdi/user.h>
|
|
|
|
#include "dahdi_tools_version.h"
|
|
|
|
|
|
|
|
#define BLOCK_SIZE 2039
|
2011-06-08 03:44:34 +08:00
|
|
|
#define DEVICE "/dev/dahdi/channel"
|
2010-08-18 21:49:24 +08:00
|
|
|
|
|
|
|
#define CONTEXT_SIZE 7
|
|
|
|
/* Prints a set of bytes in hex format */
|
|
|
|
static void print_packet(unsigned char *buf, int len)
|
|
|
|
{
|
|
|
|
int x;
|
|
|
|
printf("{ ");
|
|
|
|
for (x=0;x<len;x++)
|
|
|
|
printf("%02x ",buf[x]);
|
|
|
|
printf("}\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Shows data immediately before and after the specified byte to provide context for an error */
|
|
|
|
static void show_error_context(unsigned char *buf, int offset, int bufsize)
|
|
|
|
{
|
|
|
|
int low;
|
|
|
|
int total = CONTEXT_SIZE;
|
|
|
|
|
|
|
|
if (offset >= bufsize || 0 >= bufsize || 0 > offset ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
low = offset - (CONTEXT_SIZE-1)/2;
|
|
|
|
if (0 > low) {
|
|
|
|
total += low;
|
|
|
|
low = 0;
|
|
|
|
}
|
|
|
|
if (low + total > bufsize) {
|
|
|
|
total = bufsize - low;
|
|
|
|
}
|
|
|
|
buf += low;
|
|
|
|
printf("Offset %d ", low);
|
|
|
|
print_packet(buf, total);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Shows how the program can be invoked */
|
|
|
|
static void usage(const char * progname)
|
|
|
|
{
|
|
|
|
printf("%s: Pattern loop test\n", progname);
|
|
|
|
printf("Usage: %s <dahdi device> [-t <secs>] [-r <count>] [-b <count>] [-vh?] \n", progname);
|
|
|
|
printf("\t-? - Print this usage summary\n");
|
|
|
|
printf("\t-t <secs> - # of seconds for the test to run\n");
|
|
|
|
printf("\t-r <count> - # of test loops to run before a summary is printed\n");
|
|
|
|
printf("\t-s <count> - # of writes to skip before testing for results\n");
|
|
|
|
printf("\t-v - Verbosity (repetitive v's add to the verbosity level e.g. -vvvv)\n");
|
|
|
|
printf("\t-b <# buffer bytes> - # of bytes to display from buffers on each pass\n");
|
|
|
|
printf("\n\t Also accepts old style usage:\n\t %s <device name> [<timeout in secs>]\n", progname);
|
|
|
|
}
|
|
|
|
|
2011-06-08 03:44:34 +08:00
|
|
|
int channel_open(const char *name, int *bs)
|
|
|
|
{
|
|
|
|
int channo, fd;
|
|
|
|
struct dahdi_params tp;
|
|
|
|
struct stat filestat;
|
|
|
|
|
|
|
|
/* stat file, if character device, open it */
|
|
|
|
channo = strtoul(name, NULL, 10);
|
|
|
|
fd = stat(name, &filestat);
|
|
|
|
if (!fd && S_ISCHR(filestat.st_mode)) {
|
|
|
|
fd = open(name, O_RDWR, 0600);
|
|
|
|
if (fd < 0) {
|
|
|
|
perror(name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
/* try out the dahdi_specify interface */
|
|
|
|
} else if (channo > 0) {
|
|
|
|
fd = open(DEVICE, O_RDWR, 0600);
|
|
|
|
if (fd < 0) {
|
|
|
|
perror(DEVICE);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (ioctl(fd, DAHDI_SPECIFY, &channo) < 0) {
|
|
|
|
perror("DAHDI_SPECIFY ioctl failed");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
/* die */
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Specified channel is not a valid character "
|
|
|
|
"device or channel number");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ioctl(fd, DAHDI_SET_BLOCKSIZE, bs) < 0) {
|
|
|
|
perror("SET_BLOCKSIZE");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ioctl(fd, DAHDI_GET_PARAMS, &tp)) {
|
|
|
|
fprintf(stderr, "Unable to get channel parameters\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2010-08-18 21:49:24 +08:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
int res, x;
|
|
|
|
int i;
|
|
|
|
int bs = BLOCK_SIZE;
|
|
|
|
int skipcount = 10;
|
|
|
|
unsigned char c=0,c1=0;
|
|
|
|
unsigned char inbuf[BLOCK_SIZE];
|
|
|
|
unsigned char outbuf[BLOCK_SIZE];
|
|
|
|
int setup=0;
|
|
|
|
unsigned long bytes=0;
|
|
|
|
int timeout=0;
|
|
|
|
int loop_errorcount;
|
|
|
|
int reportloops = 0;
|
|
|
|
int buff_disp = 0;
|
|
|
|
unsigned long currentloop = 0;
|
|
|
|
unsigned long total_errorcount = 0;
|
|
|
|
int verbose = 0;
|
|
|
|
char * device;
|
|
|
|
int opt;
|
|
|
|
int oldstyle_cmdline = 1;
|
2011-07-22 01:29:34 +08:00
|
|
|
unsigned int event_count = 0;
|
2010-08-18 21:49:24 +08:00
|
|
|
|
|
|
|
/* Parse the command line arguments */
|
|
|
|
while((opt = getopt(argc, argv, "b:s:t:r:v?h")) != -1) {
|
|
|
|
switch(opt) {
|
|
|
|
case 'h':
|
|
|
|
case '?':
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(1);
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
buff_disp = strtoul(optarg, NULL, 10);
|
|
|
|
if (BLOCK_SIZE < buff_disp) {
|
|
|
|
buff_disp = BLOCK_SIZE;
|
|
|
|
}
|
|
|
|
oldstyle_cmdline = 0;
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
reportloops = strtoul(optarg, NULL, 10);
|
|
|
|
oldstyle_cmdline = 0;
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
skipcount = strtoul(optarg, NULL, 10);
|
|
|
|
oldstyle_cmdline = 0;
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
timeout = strtoul(optarg, NULL, 10);
|
|
|
|
oldstyle_cmdline = 0;
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
verbose++;
|
|
|
|
oldstyle_cmdline = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If no device was specified */
|
|
|
|
if(NULL == argv[optind]) {
|
|
|
|
printf("You need to supply a dahdi device to test\n");
|
|
|
|
usage(argv[0]);
|
|
|
|
exit (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the dahdi device name */
|
|
|
|
if (argv[optind])
|
|
|
|
device = argv[optind];
|
|
|
|
|
|
|
|
/* To maintain backward compatibility with previous versions process old style command line */
|
|
|
|
if (oldstyle_cmdline && argc > optind +1) {
|
|
|
|
timeout = strtoul(argv[optind+1], NULL, 10);
|
|
|
|
}
|
|
|
|
|
|
|
|
time_t start_time = 0;
|
|
|
|
|
2011-06-08 03:44:34 +08:00
|
|
|
fd = channel_open(device, &bs);
|
|
|
|
if (fd < 0)
|
2010-08-18 21:49:24 +08:00
|
|
|
exit(1);
|
|
|
|
ioctl(fd, DAHDI_GETEVENT);
|
|
|
|
|
|
|
|
i = DAHDI_FLUSH_ALL;
|
|
|
|
if (ioctl(fd,DAHDI_FLUSH,&i) == -1) {
|
|
|
|
perror("DAHDI_FLUSH");
|
|
|
|
exit(255);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Mark time if program has a specified timeout */
|
|
|
|
if(0 < timeout){
|
|
|
|
start_time = time(NULL);
|
|
|
|
printf("Using Timeout of %d Seconds\n",timeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ********* MAIN TESTING LOOP ************ */
|
|
|
|
for(;;) {
|
|
|
|
/* Prep the data and write it out to dahdi device */
|
|
|
|
res = bs;
|
|
|
|
for (x = 0; x < bs; x++) {
|
|
|
|
outbuf[x] = c1++;
|
|
|
|
}
|
|
|
|
|
2011-04-19 05:20:10 +08:00
|
|
|
write_again:
|
2010-08-18 21:49:24 +08:00
|
|
|
res = write(fd,outbuf,bs);
|
|
|
|
if (res != bs) {
|
2011-07-22 01:29:34 +08:00
|
|
|
if (ELAST == errno) {
|
|
|
|
ioctl(fd, DAHDI_GETEVENT, &x);
|
|
|
|
if (event_count > 0)
|
|
|
|
printf("Event: %d\n", x);
|
|
|
|
++event_count;
|
|
|
|
} else {
|
|
|
|
printf("W: Res is %d: %s\n", res, strerror(errno));
|
|
|
|
}
|
2011-04-19 05:20:10 +08:00
|
|
|
goto write_again;
|
2010-08-18 21:49:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If this is the start of the test then skip a number of packets before test results */
|
|
|
|
if (skipcount) {
|
|
|
|
if (skipcount > 1) {
|
|
|
|
res = read(fd,inbuf,bs);
|
|
|
|
}
|
|
|
|
skipcount--;
|
|
|
|
if (!skipcount) {
|
|
|
|
printf("Going for it...\n");
|
|
|
|
}
|
2011-04-19 05:20:10 +08:00
|
|
|
i = 1;
|
|
|
|
ioctl(fd,DAHDI_BUFFER_EVENTS, &i);
|
2010-08-18 21:49:24 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-04-19 05:20:10 +08:00
|
|
|
read_again:
|
2010-08-18 21:49:24 +08:00
|
|
|
res = read(fd, inbuf, bs);
|
|
|
|
if (res < bs) {
|
2011-04-19 05:20:10 +08:00
|
|
|
printf("R: Res is %d\n", res);
|
|
|
|
ioctl(fd, DAHDI_GETEVENT, &x);
|
|
|
|
printf("Event: %d\n", x);
|
|
|
|
goto read_again;
|
2010-08-18 21:49:24 +08:00
|
|
|
}
|
|
|
|
/* If first time through, set byte that is used to test further bytes */
|
|
|
|
if (!setup) {
|
|
|
|
c = inbuf[0];
|
|
|
|
setup++;
|
|
|
|
}
|
|
|
|
/* Test the packet read back for data pattern */
|
|
|
|
loop_errorcount = 0;
|
|
|
|
for (x = 0; x < bs; x++) {
|
|
|
|
/* if error */
|
|
|
|
if (inbuf[x] != c) {
|
|
|
|
total_errorcount++;
|
|
|
|
loop_errorcount++;
|
|
|
|
if (oldstyle_cmdline) {
|
|
|
|
printf("(Error %ld): Unexpected result, %d != %d, %ld bytes since last error.\n", total_errorcount, inbuf[x],c, bytes);
|
|
|
|
} else {
|
|
|
|
if (1 <= verbose) {
|
|
|
|
printf("Error %ld (loop %ld, offset %d, error %d): Unexpected result, Read: 0x%02x, Expected 0x%02x.\n",
|
|
|
|
total_errorcount,
|
|
|
|
currentloop,
|
|
|
|
x,
|
|
|
|
loop_errorcount,
|
|
|
|
inbuf[x],
|
|
|
|
c);
|
|
|
|
}
|
|
|
|
if (2 <= verbose) {
|
|
|
|
show_error_context(inbuf, x, bs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Reset the expected data to what was just read. so test can resynch on skipped data */
|
|
|
|
c = inbuf[x];
|
|
|
|
bytes=0; /* Reset the count from the last encountered error */
|
|
|
|
}
|
|
|
|
c++;
|
|
|
|
bytes++;
|
|
|
|
}
|
|
|
|
/* If the user wants to see some of each buffer transaction */
|
|
|
|
if (0 < buff_disp) {
|
|
|
|
printf("Buffer Display %d (errors =%d)\nIN: ", buff_disp, loop_errorcount);
|
|
|
|
print_packet(inbuf, 64);
|
|
|
|
printf("OUT:");
|
|
|
|
print_packet(outbuf, 64);
|
|
|
|
}
|
|
|
|
|
|
|
|
currentloop++;
|
|
|
|
/* Update stats if the user has specified it */
|
|
|
|
if (0 < reportloops && 0 == (currentloop % reportloops)) {
|
|
|
|
printf("Status on loop %lu: Total errors = %lu\n", currentloop, total_errorcount);
|
|
|
|
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
printf("(%d) Wrote %d bytes\n", packets++, res);
|
|
|
|
#endif
|
|
|
|
if(timeout && (time(NULL)-start_time) > timeout){
|
|
|
|
printf("Timeout achieved Ending Program\n");
|
|
|
|
printf("Test ran %ld loops of %d bytes/loop with %ld errors\n", currentloop, bs, total_errorcount);
|
|
|
|
return total_errorcount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2011-06-08 03:44:34 +08:00
|
|
|
|