开发者

How to use pipes for nonblocking IPC (UART emulation)

Problem:

I would like to write some test/emulation code that emulates a serial port connection. The real code looks like this:

DUT <- UART -> testtool.exe

My plan is to use create a test application (CodeUnderTest.out) on linux that forks to launch testool.out with two (read & write) named pipes as arguments. But I cannot figure out how to make all the pipe IO non-blocking!

The setup would look like this:.

CodeUnderTest.out <- named pipes -> testTool.out (lauched from CodeUnderTest.out)

I have tried opening the pipes as following:

open(wpipe,O_WRONLY|O_NONBLOCK);
open(rpipe,O_RDONLY|O_NONBLOCK);

But the write blocks until the reader opens the wpipe. Nex开发者_如何学Ct I tried the following:

open(wpipe,O_RDWR|O_NONBLOCK);
open(rpipe,O_RDONLY|O_NONBLOCK);

But then the reader of the first message never gets any data (doesn't block though)

I also tried adding open and close calls around each message, but that didn't work either...

Test code:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

pid_t pid;
char* rpipe, *wpipe,*x;
FILE *rh,*wh;
int rfd,wfd;

void openrpipe( void )
   {
   rfd = open(rpipe,O_RDONLY|O_NONBLOCK);
   rh = fdopen(rfd,"rb");
   printf("%sopeningr %x\n",x,rh);
   }
void openwpipe( void )
   {
   //Fails when reader not already opened
   //wfd = open(wpipe,O_WRONLY|O_NONBLOCK);
   wfd = open(wpipe,O_RDWR|O_NONBLOCK);
   wh = fdopen(wfd,"wb");
   printf("%sopeningw %x\n",x,wh);
   }
void closerpipe( void )
   {
   int i;
   i = fclose(rh);
   printf("%sclosingr %d\n",x,i);
   }
void closewpipe( void )
   {
   int i;
   i = fclose(wh);
   printf("%sclosingw %d\n",x,i);
   }
void readpipe( char* expect, int len)
   {
   char buf[1024];
   int i=0;
   printf("%sreading\n",x);
   while(i==0)
      {
      //printf(".");
      i = fread(buf,1,len,rh);
      }
   printf("%sread (%d) %s\n",x,i,buf);
   }
void writepipe( char* data, int len)
   {
   int i,j;
   printf("%swriting\n",x);
   i = fwrite(data,1,len,rh);
   j = fflush(rh); //No help!
   printf("%sflush %d\n",x,j);
   printf("%swrite (%d) %s\n",x,i,data);
   }
int main(int argc, char **argv)
   {
   rpipe = "readfifo";
   wpipe = "writefifo";
   x = "";
   pid = fork();
   if( pid == 0)
      {
      wpipe = "readfifo";
      rpipe = "writefifo";
      x = "   ";
      openrpipe();
      openwpipe();
      writepipe("paul",4);
      readpipe("was",3);
      writepipe("here",4);
      closerpipe();
      closewpipe();
      exit(0);
      }
   openrpipe();
   openwpipe();
   readpipe("paul",4);
   writepipe("was",3);
   readpipe("here",4);
   closerpipe();
   closewpipe();
   return( -1 );
   }

BTW:

To use the testcode above you need will need to create 2 pipes in the current dir:

mkfifo ./readfifo

mkfifo ./writefifo

UPDATE:

Okay I think I have the right settings now. Please let me know if it can be done better

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

pid_t pid;
char* rpipe, *wpipe,*x;
int rfd,wfd;

FILE* openpipe( char* str, char* access )
   {
   FILE* fh;
   rfd = open(str,O_RDWR|O_NONBLOCK);
   fh = fdopen(rfd,access);
   printf("%sopen(%s,%s)=%x\n",x,str,access,fh);
   return(fh);
   }
void closepipe( FILE* fh )
   {
   int i;
   i = fclose(fh);
   printf("%sclosing %d\n",x,i);
   }
void readpipe( char* expect, int len, FILE* fh)
   {
   char buf[1024];
   int i=0;
   printf("%sreading\n",x);
   while(i==0)
      {
      //printf("%c",strlen(x)?'.':'#');
      i = fread(buf,1,len,fh);
      }
   buf[i] = 0;
   printf("%sread (%d) %s\n",x,i,buf);
   }
void writepipe( char* data, int len, FILE* fh)
   {
   int i=0,j;
   printf("%swriting\n",x);
   //while(i==0)
   i = fwrite(data,1,len,fh);
   j=fflush(fh);
   printf("%sflush %d\n",x,j);
   printf("%swrite (%d) %s\n",x,i,data);
   }
int main(int argc, char **argv)
   {
   FILE *rh,*wh;
   rpipe = "readfifo";
   wpipe = "writefifo";
   x = "";
   pid = fork();
   if( pid == 0)
      {
      FILE *rh,*wh;
      wpipe = "readfifo";
      rpipe = "writefifo";
      x = "   ";
      rh=openpipe(rpipe,"rb");
      wh=openpipe(wpipe,"wb");
      writepipe("paul",4,wh);
      readpipe("was",3,rh);
      writepipe("here",4,wh);
      closepipe(rh);
      closepipe(wh);
      exit(0);
      }
   rh=openpipe(rpipe,"rb");
   wh=openpipe(wpipe,"wb");
   readpipe("paul",4,rh);
   writepipe("was",3,wh);
   readpipe("here",4,rh);
   closepipe(rh);
   closepipe(wh);
   return( -1 );
   }


In general, the best way to emulate a serial port for this kind of testing is to use a pseudo-terminal, since a serial port is a tty and so is a pty.

posix_openpt(), grantpt(), unlockpt() and ptsname() are the calls you will need. The master side is read and written by the device emulator, and the slave side is passed as the serial port to open to the program being tested.


Don't write to the pipe until there's a reader. You should be able to use select or poll to find out when a reader connects.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜