// simirid.c -- simulate iridium delays between two serial ports # include # include # include # include # include // for timeval # include // for timeval, gettimeofday # include // for isprint() # include // to check if pid is running # include // for settty() gettty() args # include // for open() args # include double now(void) { struct timeval tv; struct timezone tz; static time_t s0 = 0; gettimeofday(&tv,&tz); if(s0 == 0) s0 = tv.tv_sec; return (double)(tv.tv_sec - s0) + (double)(tv.tv_usec) * 1.0e-6; } void sleep_us(long us) { struct timeval timeout; if(us <= 0) return; timeout.tv_sec = us/1000000L; timeout.tv_usec = us%1000000L; select(1, NULL, NULL, NULL, &timeout); return; } int opentty(char *tty, long baud) { static struct termios settty; int ret; int baudflag; int fdtty; char ttydev[100]; // open first with no delay in order to change the bits to ignore // handshaking lines, then open again for real. sprintf(ttydev,"/dev/%s",tty); if((fdtty=open(ttydev,O_RDWR | O_NDELAY))<0){ perror("first serial port open failed"); fprintf(stderr,"ttydev=\"%s\"\n",ttydev); return -1; } if (baud == 110) baudflag = B110; else if(baud == 300) baudflag = B300; else if(baud == 600) baudflag = B600; else if(baud == 1200) baudflag = B1200; else if(baud == 2400) baudflag = B2400; else if(baud == 4800) baudflag = B4800; else if(baud == 9600) baudflag = B9600; else if(baud == 19200) baudflag = B19200; else if(baud == 38400) baudflag = B38400; else if(baud == 57600) baudflag = B57600; else if(baud == 115200) baudflag = B115200; else if(baud == 230400) baudflag = B230400; else if(baud == 460800) baudflag = B460800; else{ fprintf(stderr,"opentty(): bad baudrate=%ld\n",baud); return -2; } # if 0 if((tcgetattr(fdtty, &settty)) < 0){ perror("tcgetattr() serial port failed"); fprintf(stderr,"ttydev=\"%s\" fdtty=%d\n",ttydev,fdtty); return -6; } # endif settty.c_iflag = 0; settty.c_oflag = 0; settty.c_cflag = 0; settty.c_lflag = 0; cfmakeraw(&settty); settty.c_cflag |= CLOCAL; // ignore modem control lines settty.c_cflag &= ~CRTSCTS; // no flow control settty.c_cflag |= CREAD; // added June 21, 2002 per new tty driver cfsetispeed(&settty,baudflag); cfsetospeed(&settty,baudflag); ret=tcsetattr(fdtty,TCSANOW,&settty); if(ret<0){ perror("tcsetattr() serial port failed"); fprintf(stderr,"ttydev=\"%s\"\n",ttydev); return -3; } # if 0 if(close(fdtty) < 0){ perror("error: close() serial port open failed"); fprintf(stderr,"ttydev=\"%s\"\n",ttydev); return -4; } if((fdtty=open(ttydev,O_RDWR)) < 0){ perror("second serial port open failed"); fprintf(stderr,"ttydev=\"%s\"\n",ttydev); return -5; } # endif return fdtty; } int main(int argc, char** argv) { # define MBUF 10000 char buf1[MBUF], buf2[MBUF]; double time1[MBUF],time2[MBUF]; int head1=0, tail1=0; int head2=0, tail2=0; unsigned char kar, kar1, kar2; int seq1,seq2; int n1 = 0, n2 = 0; char *ttydev1; // leafname of tty device char *ttydev2; // leafname of tty device long baud; // baudrate in both directions double delay_min; // minimum seconds of one-way path delay double delay_max; // maximum seconds of one-way path delay double delay; long usbc; // microseconds between characters char tmp[100]; pid_t pid; FILE *fplock2; FILE *fplock1; char lockfile1[100]; char lockfile2[100]; int fdtty1; int fdtty2; int selret; double error_rate; long error_thresh; if(argc != 8){ fprintf(stderr,"usage: simirid tty1 tty2 baud delay_min delay_max " "usbc error_rate\n"); exit(1); } ttydev1 = *++argv; ttydev2 = *++argv; baud = atol(*++argv); delay_min = atof(*++argv); delay_max = atof(*++argv); usbc = atol(*++argv); error_rate = atof(*++argv); error_thresh = (double)RAND_MAX * error_rate; sprintf(lockfile1,"/var/lock/LCK..%s",ttydev1); if((fplock1 = fopen(lockfile1,"r"))!=NULL){ struct stat statbuf; // fprintf(stderr,"lock file found: %s\n",lockfile1); fscanf(fplock1,"%10d\n",&pid); fclose(fplock1); sprintf(tmp,"/proc/%d",pid); // fprintf(stderr,"checking process %s\n",tmp); if(stat(tmp,&statbuf) == -1){ // fprintf(stderr,"it is not running\n"); if(unlink(lockfile1) == -1){ perror("cannot remove lockfile1"); fprintf(stderr,"lockfile1=%s\n",lockfile1); exit(1); } fprintf(stderr,"removed stale lockfile1=%s\n",lockfile1); } else{ fprintf(stderr,"lockfile1=%s indicates processs %d is using %s\n", lockfile1,pid,ttydev1); fprintf(stderr,"exiting\n"); exit(1); } } sprintf(lockfile2,"/var/lock/LCK..%s",ttydev2); if((fplock2 = fopen(lockfile2,"r"))!=NULL){ struct stat statbuf; // fprintf(stderr,"lock file found: %s\n",lockfile2); fscanf(fplock2,"%10d\n",&pid); fclose(fplock2); sprintf(tmp,"/proc/%d",pid); // fprintf(stderr,"checking process %s\n",tmp); if(stat(tmp,&statbuf) == -1){ // fprintf(stderr,"it is not running\n"); if(unlink(lockfile2) == -1){ perror("cannot remove lockfile2 2"); fprintf(stderr,"lockfile2 %s\n",lockfile2); exit(1); } fprintf(stderr,"removed stale lockfile2 %s\n",lockfile2); } else{ fprintf(stderr,"lockfile2 %s indicates processs %d is using %s\n", lockfile2,pid,ttydev2); fprintf(stderr,"exiting\n"); exit(1); } } if((fdtty1 = opentty(ttydev1, baud)) < 0){ fprintf(stderr,"opentty failed "); fprintf(stderr,"ttydev1=%s fdtty1=%d\n",ttydev1,fdtty1); unlink(lockfile1); exit(1); } if((fdtty2 = opentty(ttydev2, baud)) < 0){ fprintf(stderr,"opentty failed "); fprintf(stderr,"ttydev2=%s fdtty2=%d\n",ttydev2,fdtty2); unlink(lockfile1); unlink(lockfile2); exit(1); } while(1){ int nfds; fd_set readfds; struct timeval timeout; if(fdtty1 > fdtty2) nfds = fdtty1 + 1; else nfds = fdtty2 + 1; FD_ZERO(&readfds); FD_SET(fdtty1,&readfds); FD_SET(fdtty2,&readfds); timeout.tv_sec = 0; timeout.tv_usec = 1000L; // 1 ms timeout selret = select(nfds, &readfds, NULL, NULL, &timeout); if(selret < 0){ perror("select failed"); fprintf(stderr," selret=%d\n",selret); goto cleanupandexit; } if(selret > 0){ // something's available // this sleep_us simulates slow bit rate over RF link // by causing time1 and time2 to be increased in order // to delay output sleep_us(usbc); if(FD_ISSET(fdtty1,&readfds)){ if(read(fdtty1, (char*)(&kar), 1) != 1){ perror("read fdtty1 failed"); goto cleanupandexit; } if(0 && kar == 0xFF){ perror("fdtty1 read 0xFF character -- cannot use with telnet\n"); goto cleanupandexit; } if((long)(rand()) < error_thresh) kar = rand() & 0xFF; buf1[head1] = kar; delay = delay_min + (delay_max - delay_min) * (double)rand() / (double)(RAND_MAX); time1[head1] = now() + delay; head1++; if(head1 >= MBUF) head1=0; } if(FD_ISSET(fdtty2,&readfds)){ if(read(fdtty2, (char*)(&kar), 1) != 1){ perror("read fdtty2 failed"); goto cleanupandexit; } if(0 && kar == 0xFF){ perror("fdtty1 read 0xFF character -- cannot use with telnet\n"); goto cleanupandexit; } if((long)(rand()) < error_thresh) kar = rand() & 0xFF; buf2[head2] = kar; delay = delay_min + (delay_max - delay_min) * (double)rand() / (double)(RAND_MAX); time2[head2] = now() + delay; head2++; if(head2 >= MBUF) head2=0; } } // the following is executed every input character or select timeout if(head1 != tail1 && now() > time1[tail1]){ kar = buf1[tail1]; tail1++; if(tail1 >= MBUF) tail1=0; n1++; if(n1 == 2) seq1=kar-32; if(n1 == 3){ if(kar!='Y' && kar!='N') fprintf(stderr,"\n"); fprintf(stderr,"h1: %2d-%c ",seq1,kar); kar1=kar; } if(kar == 0x01) n1=0; if(kar == 0x0d){ // fprintf(stderr,"h1: %2d-%c ",seq1,kar1); fprintf(stderr,"n1: %4d ",n1); } if(write(fdtty2,&kar,1) != 1){ perror("write fdtty2 failed"); goto cleanupandexit; } } if(head2 != tail2 && now() > time2[tail2]){ kar = buf2[tail2]; tail2++; if(tail2 >= MBUF) tail2=0; n2++; if(n2 == 2) seq2=kar-32; if(n2 == 3){ if(kar!='Y' && kar!='N') fprintf(stderr,"\n"); fprintf(stderr,"h2: %2d-%c ",seq2,kar); kar2=kar; } if(kar == 0x01) n2=0; if(kar == 0x0d){ // fprintf(stderr,"h2: %2d-%c ",seq2,kar2); fprintf(stderr,"n2: %4d ",n2); } if(write(fdtty1,&kar,1) != 1){ perror("write fdtty1 failed"); goto cleanupandexit; } } } unlink(lockfile1); unlink(lockfile2); fprintf(stderr,"simirid normal exit\n"); exit(0); cleanupandexit: unlink(lockfile1); unlink(lockfile2); fprintf(stderr,"simirid cleanup and exit\n"); exit(1); }