如何使用管道进行非阻塞 IPC(UART 仿真)

发布于 2024-10-08 11:28:39 字数 4236 浏览 7 评论 0原文

问题:

我想编写一些模拟串行端口连接的测试/模拟代码。这 真实的代码如下所示:

DUT <- UART ->测试工具.exe

我的计划是在 Linux 上创建一个测试应用程序 (CodeUnderTest.out),该应用程序分叉以两个(读和写)命名管道作为参数来启动 testtool.out。但我不知道如何使所有管道 IO 非阻塞!

设置看起来像这样:

CodeUnderTest.out <- 命名管道 -> testTool.out(从 CodeUnderTest.out 启动)

我尝试按如下方式打开管道:

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

但是写入会阻塞,直到读取器打开 wpipe。接下来我尝试了以下操作:

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

但是第一条消息的阅读器永远不会获取任何数据(尽管不会阻塞)

我还尝试在每条消息周围添加打开和关闭调用,但这也不起作用...

测试代码:

#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 );
   }

顺便说一句:

要使用上面的测试代码,您需要在当前目录中创建 2 个管道:

mkfifo ./readfifo

mkfifo ./writefifo

更新:

好的,我想我现在有正确的设置。请告诉我是否可以做得更好

#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 );
   }

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. Next 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 );
   }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

巴黎夜雨 2024-10-15 11:28:39

一般来说,模拟串行端口进行此类测试的最佳方法是使用伪终端,因为串行端口是 tty,因此是 pty

posix_openpt()grantpt()unlockpt()ptsname() 是您需要的调用。 Master端通过设备模拟器进行读写,Slave端作为串口打开给被测试的程序。

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.

〃温暖了心ぐ 2024-10-15 11:28:39

在有读取器之前不要写入管道。您应该能够使用 selectpoll 来确定阅读器何时连接。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文