31 (13.01.2011 00:01:18 отредактировано Peter)

Я наскоро посмотрел, что это такое.
Однажды в Qt я сам сделал класс для COM-порта для Linux и базовый для него тоже,
т.к. меня не устраивал имеющийся в Qt базовый класс, что-то похожее на IODEVICE.

Там есть пример, работает ли он у вас? Он почему-то для работы с /dev/ttyUSB0.

На чистом C++ я реальных программ не писал, если бы потребовалось, сделал бы
что-нибудь попроще, ориентируясь на класс для Qt.
Точнее, у меня было 2-3 программы для Windows, но они не работали с COM-портом.

Мне это кажется излишне сложным. Если у вас программа на  C++, то ничто не
мешает работать с COM-портом так же, как в программе на C, т.е. самому открыть
порт, установить свойства, написать программы для чтения и записи для конкретного
протокола связи и ими пользоваться. Это будет и быстрее, чем в примере, где чтение
из порта посимвольное.

Пётр.

Пётр.

32

Привет всем
Спасибо большое, Peter, за участие smile

Peter пишет:

На чистом C++ я реальных программ не писал, если бы потребовалось, сделал бы что-нибудь попроще...

Так я и сделал как можно проще...
Объясните мне непонятливому, пожалуйста :rolleyes: , с чем связано такое поведение:

Делаю две проги на запись и чтение

int  open_port(void)
{
    int fd;
    fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY |O_NONBLOCK);
    if (fd == -1)
    perror("open_port: Unable to open /dev/ttyS0 - "); 
    else
    {
    struct termios options; 
    tcgetattr(fd, &options);
    cfsetispeed(&options, B115200);
    cfsetospeed(&options, B115200);
    options.c_cflag &= ~PARENB; 
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;
    tcsetattr(fd, TCSANOW, &options);
    }                
    fcntl(fd, F_SETFL, 0);
     return (fd);
}
...
int n = write(fd,"STROKA\n",6);

...
int n ;
while(n != -1)
{
       n = read(fd,&ch,1);
       ....
}                                       

И тут начинается самое интересно oO
- Кольцо - запускаю ридера в одном сеансе, а запись в другом - чтение подвисает(как я и писал...), даже не выполняется printf перед read
- Кольцо - запускаю прослушку  cat /dev/ttyS0 и она срабатывает:  отображается строка и ждет...
- Ставлю заглушку на один порт - ридер работает нормально, в случаи побайтового считывания. В противном случаи зацикливается и выводит то по 2 символа, то по 3 и кракозябру....

33 (20.01.2011 21:04:02 отредактировано Peter)

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

1) Не вижу тут двух портов;
2) Было бы логичнее, если бы open_port принимала как аргумент ссылку на fd
    в основной программе, хотя можно и так;
3) При вызовах системных функций лучше использовать символические имена для флагов,
    а не константы. Что вы подразумевали в вызове fcntl? В open указано ведь O_RDWR.
4) Что вы называете сеансом? Вообще проверить кольцо из двух портов можно и в одной
   программе и с помощью двух независимых, одна из которых пишет, а другая читает.

Вот пример работающей программы, в case 1, 2, 4, 5 она пишет в порт и ждёт ответа,
в case 3 она, кроме этого, начиная со 2-го раза для записи ждёт, когда другая сторона
выставит сигнал DSR.

Как здесь делать вложение, я не помню. Текст можно привести в читаемый вид с помощью
команды indent.

Пётр.

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <stdbool.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#ifndef _STDIO_H
#include <stdio.h>
#endif
#ifndef _STDLIB_H
#include <stdlib.h>
#endif
#ifndef _STRING_H
#include <string.h>
#endif
#ifndef __USE_MISC
typedef unsigned int uint;
#endif
#define MSGSIZE 72
#define CAS_SIZE 10
#define CAS_NUM 10
#define MINI(n1,n2) ((n1<=n2)?n1:n2)
typedef unsigned char uchar;
int readto(int,char*);
extern int errno;
int main(int argc,char **argv){
struct timespec tds;    //,tdw;
struct timeval tv1,tv2;
struct timezone tz1,tz2;
struct termios oldcomio,newcomio;
fd_set rdsetcur,rdsetold;
int ibdrt[20]={B0,B50,B75,B110,B134,B150,B200,B300,B600,B1200,B1800,B2400,
    B4800,B9600,B19200,B38400,B57600,B115200,B230400,0},i=argc,ibr=14,
    ibrrl[10]={300,600,1200,2400,4800,9600,19200,38400,57600,115200},
    icom=1,fd,fdcom,n1,n2,n3,n4,ifd,istr,ivt=60,numcm,numex,nd=2,
    nw=4,ncyc=0,nt1,idv=1,idsr,j;
clock_t time;
uint iw=1,nz;
bool bds;
char nmcom[16],buf[80],bufrm[80];
strcpy(buf,"/usr/local/etc");if(i>1){strcpy(buf,argv[1]);fprintf(stdout,"%d %s\n",strlen(buf),buf);}
strcpy(buf+strlen(buf),"/chpa2_d.in");
FILE *fin=fopen(buf,"r");
if(fin!=NULL){
    fscanf(fin,"%d%[^\n]",&ibr,buf+32);
    fscanf(fin,"%d%[^\n]",&icom,buf+32);
    fscanf(fin,"%d%[^\n]",&nd,buf+32);
    fscanf(fin,"%d%[^\n]",&nw,buf+32);
    fscanf(fin,"%d%[^\n]",&ivt,buf+32);
    fscanf(fin,"%d%[^\n]",&idv,buf+32);
    fclose(fin);
}
strcpy(buf+30,"origcom ");
if(idv==1){strcpy(nmcom,"/dev/ttySx");sprintf(nmcom+9,"%1d",icom-1);//to COM
sprintf(bufrm," - COM-port, %1d",icom);buf[37]=nmcom[9];}
else{strcpy(nmcom,"/dev/USB0");strcpy(bufrm, " USB<->COM,   ");buf[37]='u';}
nz=(uint)((11.*1.e+9)/(double)ibrrl[ibr-8]);
fprintf(stdout,"%s%s %d%8d%8d%8u %d %s\n",
nmcom,bufrm,ibr,ibdrt[ibr],ibrrl[ibr-8],nz,ivt,buf);
sprintf(buf,"U1I%02d %02d\r",nw,nd);nd*=10;nw*=10;strcpy(buf+10,"U1R\r");
strcpy(buf+15,"U1N\r");strcpy(buf+20,"U1T\r");strcpy(buf+25,"U1P\r");
tds.tv_sec=0;tds.tv_nsec=100000000L;fprintf(stdout,"%d %d\n",nd,nw);
FD_ZERO(&rdsetold);FD_SET(0,&rdsetold);
fd=open(nmcom,O_RDWR|O_NOCTTY|O_ASYNC );
if(fd<0){perror(nmcom);exit(-1); }
if((fdcom=open(buf+30,O_WRONLY|O_CREAT|O_EXCL,0644))!=-1){
    tcgetattr(fd,&oldcomio); /* save current port settings */
    write(fdcom,(void*)&oldcomio,sizeof(oldcomio));
    close(fdcom);}
else if(errno==EEXIST){
    fdcom=open(buf+30,O_RDONLY);
    read(fdcom,(void*)&oldcomio,sizeof(oldcomio));
    tcsetattr(fd,TCSANOW,&oldcomio);
    close(fdcom);}
bzero(&newcomio, sizeof(newcomio));
newcomio.c_cflag = ibdrt[ibr] | CS8 | CLOCAL | CREAD;
newcomio.c_iflag = IGNPAR | IGNBRK;
/* set input mode (non-canonical, no echo,...) */
newcomio.c_cc[VEOF]=0;newcomio.c_cc[VEOL]=0;newcomio.c_cc[VEOL2]=0;
newcomio.c_cc[VTIME]=ivt;   /* inter-character timer unused */
newcomio.c_cc[VMIN]=0;   /* blocking read until 5 chars received */
cfsetispeed(&newcomio,ibdrt[ibr]);cfsetospeed(&newcomio,ibdrt[ibr]);
tcflush(fd,TCIOFLUSH);
tcsetattr(fd,TCSANOW,&newcomio);//fcntl(fd,F_SETFL,O_ASYNC);
FD_ZERO(&rdsetold);FD_SET(0,&rdsetold);
while(iw==1){
  rdsetcur=rdsetold;
  fprintf(stdout,"%s","enter istr, numcom and numex ");fflush(stdout);
  ifd=select(1,&rdsetcur,NULL,NULL,NULL);
  if(ifd>0){
    if(FD_ISSET(0,&rdsetcur)){
        read(0,bufrm,MSGSIZE);sscanf(bufrm,"%d%d%d",&istr,&numcm,&numex);}
    else{iw=0;istr=0;}}
  else{iw=0;istr=0;}
  fprintf(stdout,"%3d entered:%2d %d %d\n",ifd,istr,numcm,numex);
  if(istr==1){n1=0;n3=4;
    switch(numcm){
    case 1:case 2:case 4:case 5:if(numcm==1)n3=9;else n1=10+(numcm-2)*5;
      n2=write(fd,(void*)(buf+n1),n3);if(n2==-1){
      fprintf(stdout,"w %d %s\n",errno,strerror(errno));exit(-1);}
      sprintf(buf+30," !!!");n2=readto(fd,buf+30);if(n2==-1){
      fprintf(stdout,"r %d %d %s\n",numcm,errno,strerror(errno));exit(-1);}
      fprintf(stdout,"numcm=%d %d %s\n",numcm,n2,buf+30);break;
    case 3:
        ncyc=numex;gettimeofday(&tv1,&tz1);bds=0;
      for(i=0;i<ncyc;i++){gettimeofday(&tv2,&tz2);sprintf(buf+30," !!!");
        nt1=(tv2.tv_sec-tv1.tv_sec)*1000000+tv2.tv_usec-tv1.tv_usec;tv1=tv2;
        tcflush(fd,TCIOFLUSH);n2=write(fd,(void*)(buf+15),4);if(n2==-1){fprintf(
        stdout,"w %d %s\n",errno,strerror(errno));exit(-1);}n4=readto(fd,buf+30);
        if(n4==-1){fprintf(stdout,"r %d %d %s\n",numcm,errno, strerror(errno));
        exit(-1);}fprintf(stdout,"numcm=%d %d %d %d%s %d\n",numcm,i,n2,n4,buf+30
        ,nt1/1000);time=clock();j=0;if(i==0)goto lbds;while(bds&&clock()-time<60
        *CLOCKS_PER_SEC){ioctl(fd,TIOCMGET,&idsr);bds=idsr&TIOCM_DSR;if(bds){
        sprintf(buf+30,"**");n4=readto(fd,buf+30);if(n4>0){fprintf(stdout,
        "1 inf %d %d %s\r",n4,j,buf+31);j++;nanosleep(&tds,NULL);}}}if(bds){fputs
        ("\nDSR not reset!\n",stdout);break;}lbds:while(!bds&&clock()
        -time<60*CLOCKS_PER_SEC){ioctl(fd,TIOCMGET,&idsr);bds=TIOCM_DSR&idsr;if(
        !bds){sprintf(buf+30,"**");n4=readto(fd,buf+30);if(n4>0){fprintf(stdout,
        "0 inf %d %d %s\r",n4,j,buf+31);j++;nanosleep(&tds,NULL);}}}if(!bds
        ){fputs("\nNo DSR!\n",stdout);break;}
      }break;
    default:;}
      }
    else iw=0;
}
    tcsetattr(fd,TCSANOW,&oldcomio);
    close(fd);
return 0;}

int readto(int fd,char* buf){
//reads from fd to buf+1 bytes until '\r' with timeout VTIME/10.
int nb=1;
ssize_t nr;
  while(*(buf+nb-1)!='\r'){nr=read(fd,(void*)(buf+nb),1);
    if(nr<=0){if(nb==1){if(buf[0]==' ')fprintf(stdout,"timeout at 1st\n");
    nb=0;}break;}
    else{if(buf[0]!=' ')fprintf(stdout,"readto: %d %d\n",nb,buf[nb]);nb++;}}
  if(nb>1){if(buf[nb-1]=='\r')buf[nb-1]=0;else buf[nb]=0;}
return nb-1;}


// chpa2_d.in

14  ibr, 15 - 38400
1   icom, 1 - ttyS0
2   nd in sec
4   nw in sec
60  ivt in 0.1s
1   idv, 1/2 - COM/USB
Пётр.

34

Привет всем
Спасибо за пример, Peter smile 

Прошу прощения, что не четко представил инфу smile

По подобию Serial Programming HOWTO
http://rampex.ihep.su/Linux/linux_howto … WTO-1.html, я нацарапал две проги (для чистоты эксперемента) чтение:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>

int  open_port(void);

void main()
{
   int fd = open_port();
   if (fd < 0)
      exit(-1)
   int n ;
   while(n != -1)
   {
        if (n == -1)
           break;
       // Получается считывать только по-байтно
       n = read(fd,&ch,1);
       ....
    }         
}

int  open_port(void)
{
    int fd;
    fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY |O_NONBLOCK);
    if (fd == -1)
    perror("open_port: Unable to open /dev/ttyS0 - "); 
    else
    {
    struct termios options; 
    tcgetattr(fd, &options);
    cfsetispeed(&options, B115200);
    cfsetospeed(&options, B115200);
    options.c_cflag &= ~PARENB; 
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;
    tcsetattr(fd, TCSANOW, &options);
    }
    /*
    Если не вставить эту стороку в ридере - вылет из цикла
    while по break - С чем это связано???????
    */                
    fcntl(fd, F_SETFL, 0);  
     return (fd);
}

Ну а запись в порт - тоже самое, только меняю порт и передаю тестовую стороку:

...
int n = write(fd,"STROKA\n",6);
...

   
Теперь запускаю ридера во одном командере, а райтера - в другом...
Ну результат, как и писал - чтение зависло в ожидании, если кольцо.
Так же и с готовым примером из источника выше...
А если заглушка на один порт - нормально считывается только по-байтно...

35

Я никогда не пытался писать и читать один и тот же порт и не задумывался
о том, как это возможно. Данные, которые пишутся в порт, из него только
уходят, они не поступают в него, в его буфер приёма.
Если же записанные в него данные не считываются приёминком на другом
конце кабеля, то я не помню, что будет, в лучшем случае они просто будут
постепенно перезаписываться

Если ваша заглушка - это перемыкание TxD-RxD, то, м.б., и будет работать
запись/чтение на одном порту.

Если на вашем компьютере два COM-порта, то их надо соединить модемным
кабелем, в одной программе писать в 1-й порт, а в другой из 2-го читать.
В одной программе открыть 1-й порт только для записи, в другой открыть 2-й
только для чтения, но можно и оба для чтения/записи.

Структуру termios хорошо бы объявлять в главной программе, чтобы она
существовала всё время её работы, хотя это не обязательно. Если уж
параметры порта устанавливаются через неё, то её тоже хорошо бы обнулять
перед установкой параметров.

Мне непонятно, почему порт открывается с флаом O_NONBLOCK, вроде бы надо
без него.
Откуда вы взяли

fcntl(fd,S_SETFL,0);

и что такое в ней 0? 0 - это значение флага O_RDONLY.
У меня же программа работает без вызова fcntl.

Моя программа тоже читает посимвольно. В вашей write передаётся 6 символов,
а в строке их 7.

Что касается зависаний и ожидания прихода символа, то посмотрите описание
параметрво termios c_cc[VTIME] и c_cc[VMIN].

Пётр.

Пётр.

36

Привет всем
Спасибо большое, Peter, ответ и потраченное на меня время smile
Буду еще внимательнее читать инфо...