LinuxForum.Fans
Тема

Создать кольцо двух СOM-портов

Автор: DimonK 36 сообщений 11106 просмотров
#103924

Привет всем

voral написал:
Ясно. Достаточно не сложный протокол.
voral, я тут накопал примеров работы с modbus(master-sleve) на сях, подскажите, пожалуйста, можно их будет применить(интерпретировать) к dibus. Возможно это не корректный вопрос, но мой уровень не позволяет большего :( ...
#103928
DimonK написал:
voral, я тут накопал примеров работы с modbus(master-sleve) на сях, подскажите, пожалуйста, можно их будет применить(интерпретировать) к dibus. Возможно это не корректный вопрос, но мой уровень не позволяет большего :( ...

все зависит от примеров.... В любом случае в примерах стоит изучить и понять как все сделано. А там уж видно будет. Вообще в таких вещах брать чужой код опасно не разобравшись - баг вылезет замучаешься искать. Мало ли в алгоритме автор заложил копированием памяти что то кудато прописывать характерное для модбаса в неожиданном месте......

К тому же я в dibus не вчитывался особо - взглянул по диагонали :)

#104092

Привет всем
Ладно, будем что-то думать...

#108975

Привет всем
Обращаюсь снова к Вам за помощью :rolleyes:
Тут меня "до глубины душевной" проблема тронула. Поняв, что порт на отрез отказывается со мнос сотрудничать, я максимально упростил пример от сюда http://libserial.sourceforge.net: открываю порт, устанавливаю значение структуры termios newtio и сохраняю настройки -

tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);

Затем в отладчике проганяю прогу и командой setserial просматриваю параметры порта - НИ КАКОЙ РАЗНИЦЫ - параметры не поменялись :( :O
Подскажите, пожалуйста, с чем это связано?

#109175

Я не пользуюсь отладчиком и у меня не бывало таких чудес, чтобы tcsetattr
не выполнилась. setserial для проверки програмы тоже никогда не использовал.
Надо понять, что надо от порта и эти параметры установить.
"man termios" достаточно подробный. Правда, когда я только начинал работать
с COM-портом, я пользовался книгой на русском, где termios очень подробно
описана. Это было лет 10 назад.

Пётр.

#110817

Peter написал:
...Надо понять, что надо от порта...
- Наладить обмен между двумя компами....
Я не понимаю, почему я не могу менять настройки портов с помощью с-х функций oO
#111099

Я как-то не имел с этим проблем ни в DOS, ни в Windows, ни в Linux.
Обмен всегда делается по определёному протоколу, вот и реализуйте его.
Если сомневаетесь, что tcsetattr выполняется, проверьте с помощью
tcgetattr. М.б., она выполняется, но не так, как вам хочется.
Если вы устанавливаете параметры порта с помощью termios, то вы его
полный хозяин, как напишете, так и будет работать.

Пётр.

#113767

Привет всем
С Новым Годом и Рождеством Христовым! smile

Объясните, пожалуйста, что я не так делаю :rolleyes:
Я просто сделал две проги одна пишет, другая читает (фиг уж с этими настройками!). Так вот чтение зависает...
strace показало: read(3 ... - зависание...
Тоже и с утилой cat - виснет зараза: в консоле(при записи) отобразилась сторока(из используемого файла), курсор остановился после последнего символа и завис (вроде должно перейти к готовности принятия команд?). На чтение - сразу виснет :(
Вот чё это за ...

#113877

Поскольку мы не знаем, что вы делаете, поэтому не можем сказать, что вы делаете не так.
Я тоже однажды сделал две коротких программы, одна консольная в Linux, другая
с небольшим окном в Windows, обменивались данными через COM-порт. Одна посылала
строку, другая принимала, выводила на экран и посылала обратно, 1-я её принимала,
выводила и посылал новую.

То, что чтение зависает, видно и без strace. Либо неправильно настроена termios,
не в соответствии с протоколом, либо неправильно вызывается системная read.
У меня всегда была подпрограмма чтения, уже из которой вызывалась read,
т.к. были разные протоколы обмена.

Пётр.

#116025

Привет всем

Peter написал:
Поскольку мы не знаем, что вы делаете, поэтому не можем сказать, что вы делаете не так. Пётр.
- хотел протестировать скачанные проги
http://sourceforge.net/projects/libserial/- Не получилось :(
Заием решил протестировать на уровне утилит - результат тот-же :(
(создаю файл с текстом; в одной раб. панеле записываю этот файл в порт: cat; в другой - считываю из порта....)
#116275

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

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

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

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

Пётр.

#118831

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

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

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

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

text

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 и кракозябру....

#119098

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

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

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

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

Пётр.

text

#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

#120867

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

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

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

text

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

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

#121184

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

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

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

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

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

text
fcntl(fd,S_SETFL,0);

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

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

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

Пётр.

#121784

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

Войдите или зарегистрируйтесь, чтобы ответить.