Как использовать каналы для неблокирующего IPC (эмуляция UART) - PullRequest
1 голос
/ 22 декабря 2010

Проблема:

Я хотел бы написать код теста / эмуляции, который эмулирует соединение через последовательный порт. реальный код выглядит так:

DUT <- UART -> testtool.exe

Мой план состоит в том, чтобы создать в Linux тестовое приложение (CodeUnderTest.out), которое запускает testool.out с двумя именованными каналами (чтение и запись) в качестве аргументов. Но я не могу понять, как сделать все операции ввода-вывода трубы неблокирующими!

Настройка будет выглядеть следующим образом:.

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

UPDATE:

Хорошо, я думаю, у меня сейчас правильные настройки. Пожалуйста, дайте мне знать, если это можно сделать лучше

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

Ответы [ 2 ]

1 голос
/ 22 декабря 2010

В общем, лучший способ эмулировать последовательный порт для этого вида тестирования - использовать псевдотерминал, поскольку последовательный порт - это tty, а также pty.

posix_openpt(), grantpt(), unlockpt() и ptsname() - звонки, которые вам понадобятся.Ведущая сторона считывается и записывается эмулятором устройства, а ведомая сторона передается в качестве последовательного порта для открытия тестируемой программе.

0 голосов
/ 22 декабря 2010

Не пишите в трубу, пока не появится читатель. Вы должны быть в состоянии использовать select или poll, чтобы узнать, когда подключается ридер.

...