Не в состоянии читать любые данные, используя модем на Ubuntu - PullRequest
0 голосов
/ 17 марта 2019

Я пытаюсь прочитать данные из последовательного порта и взял пример кода отсюда:

http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html

Пример кода:

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

/* baudrate settings are defined in <asm/termbits.h>, which is
included by <termios.h> */
#define BAUDRATE B9600     
//B38400            
/* change this definition for the correct port */
#define MODEMDEVICE "/dev/ttyACM0"
#define _POSIX_SOURCE 1 /* POSIX compliant source */

#define FALSE 0
#define TRUE 1

volatile int STOP=FALSE; 

main()
{
  printf("starting program\n");

          int fd,c, res;
          struct termios oldtio,newtio;
          char buf[255];
        /* 
          Open modem device for reading and writing and not as controlling tty
          because we don't want to get killed if linenoise sends CTRL-C.
        */
         fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY ); 
         if (fd <0) {perror(MODEMDEVICE); exit(-1); }

         printf("fd=%d\n", fd);

         tcgetattr(fd,&oldtio); /* save current serial port settings */
         bzero(&newtio, sizeof(newtio)); /* clear struct for new port settings */

        /* 
          BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
          CRTSCTS : output hardware flow control (only used if the cable has
                    all necessary lines. See sect. 7 of Serial-HOWTO)
          CS8     : 8n1 (8bit,no parity,1 stopbit)
          CLOCAL  : local connection, no modem contol
          CREAD   : enable receiving characters
        */
         newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;

        /*
          IGNPAR  : ignore bytes with parity errors
          ICRNL   : map CR to NL (otherwise a CR input on the other computer
                    will not terminate input)
          otherwise make device raw (no other input processing)
        */
         newtio.c_iflag = IGNPAR | ICRNL;

        /*
         Raw output.
        */
         newtio.c_oflag = 0;

        /*
          ICANON  : enable canonical input
          disable all echo functionality, and don't send signals to calling program
        */
         newtio.c_lflag = ICANON;

        /* 
          initialize all control characters 
          default values can be found in /usr/include/termios.h, and are given
          in the comments, but we don't need them here
        */
         newtio.c_cc[VINTR]    = 0;     /* Ctrl-c */ 
         newtio.c_cc[VQUIT]    = 0;     /* Ctrl-\ */
         newtio.c_cc[VERASE]   = 0;     /* del */
         newtio.c_cc[VKILL]    = 0;     /* @ */
         newtio.c_cc[VEOF]     = 4;     /* Ctrl-d */
         newtio.c_cc[VTIME]    = 0;     /* inter-character timer unused */
         newtio.c_cc[VMIN]     = 1;     /* blocking read until 1 character arrives */
         newtio.c_cc[VSWTC]    = 0;     /* '\0' */
         newtio.c_cc[VSTART]   = 0;     /* Ctrl-q */ 
         newtio.c_cc[VSTOP]    = 0;     /* Ctrl-s */
         newtio.c_cc[VSUSP]    = 0;     /* Ctrl-z */
         newtio.c_cc[VEOL]     = 0;     /* '\0' */
         newtio.c_cc[VREPRINT] = 0;     /* Ctrl-r */
         newtio.c_cc[VDISCARD] = 0;     /* Ctrl-u */
         newtio.c_cc[VWERASE]  = 0;     /* Ctrl-w */
         newtio.c_cc[VLNEXT]   = 0;     /* Ctrl-v */
         newtio.c_cc[VEOL2]    = 0;     /* '\0' */

        /* 
          now clean the modem line and activate the settings for the port
        */
         tcflush(fd, TCIFLUSH);
         tcsetattr(fd,TCSANOW,&newtio);
         printf("tcsetattr returned %d\n", res);
         printf("just before while STOP loop\n");        
        /*
          terminal settings done, now handle input
          In this example, inputting a 'z' at the beginning of a line will 
          exit the program.
        */
         while (STOP==FALSE) {     /* loop until we have a terminating condition */
         /* read blocks program execution until a line terminating character is 
            input, even if more than 255 chars are input. If the number
            of characters read is smaller than the number of chars available,
            subsequent reads will return the remaining chars. res will be set
            to the actual number of characters actually read */
             printf("just before read\n");
             res = read(fd,buf,255); 
            printf("just after read\n");

            buf[res]=0;             /* set end of string, so we can printf */
            printf(":%s:%d\n", buf, res);
            if (buf[0]=='z') STOP=TRUE;
         }
         /* restore the old port settings */
         tcsetattr(fd,TCSANOW,&oldtio);
        }

И я скомпилировал и запустил так:

sudo ./a.out

Но единственный вывод, который я получаю:

starting program
fd=3
tcsetattr returned 0
just before while STOP loop
just before read

Я пытался дозвониться до модема, используя мой мобильный телефон, но ничего.

если я делаю ls / dev / ttyA * я вижу / dev / ttyACM0

Нужно ли как-то настраивать порт?

Модем - это голосовой модем Conexant 93010. Это определенно работает. Есть небольшое осложнение, что я запускаю Ubuntu на VMWare VM. Но я подключаюсь к виртуальной машине, и когда я подключаю устройство, я вижу ttyACM0.

UPDATE

Я обнаружил в тестировании, что я действительно получаю вывод, но он очень задерживается. Например, если я звоню, мне в конечном итоге отображается RING Но я должен постоянно звонить через модем, прерывать линию и звонить снова. После 15 звонков вижу выходной. Я изменил чтение только на 5 символов за раз. Почему задержка?

Если я изменяю вызов чтения на чтение 10 символов за раз, это то же самое поведение. Требуется 15-16 звонков, прежде чем я вижу какие-либо данные, напечатанные на экране (все эти кольца).

Я запускаю серийный код в Windows, и нет задержки. Так что это не аппаратное обеспечение.

1 Ответ

0 голосов
/ 19 марта 2019

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

newtio.c_lflag = ICANON;
...
newtio.c_cc[VEOF]     = 4;     /* Ctrl-d */
...
newtio.c_cc[VEOL]     = 0;     /* '\0' */
....
newtio.c_cc[VEOL2]    = 0;     /* '\0' */

Согласно документации для termios :

Канонический и неканонический режим

Установка флага канона ICANON в c_lflag определяет, будет ли терминал работает в каноническом режиме (набор ICANON) или неканон- реальный режим (ICANON не установлен). По умолчанию ICANON установлен.

В каноническом режиме:

  • Ввод доступен построчно. Доступна строка ввода когда введен один из разделителей строк (NL, EOL, EOL2; или EOF в начало строки). За исключением случая EOF, разделитель строк включен в буфер, возвращаемый read (2).

Похоже, что здесь происходит то, что буфер ядра в конечном итоге заполняется и отправляет вам информацию обратно, или вы получаете один из управляющих символов (возможно, неосторожно).

В любом случае, попробуйте установить newio.c_lflag в 0; это должно очистить канонический режим ввода. Эта связанная проблема также может помочь.


Обычно я очищаю все настройки termios следующим образом, а затем устанавливаю их соответствующим образом:

struct termios newio;
if( tcgetattr(fd, &newio) < 0 ){
   /* Error checking */
}
newio.c_iflag |= IGNBRK;
newio.c_iflag &= ~BRKINT;
newio.c_iflag &= ~ICRNL;
newio.c_oflag = 0;
newio.c_lflag = 0;
newio.c_cc[VTIME] = 0;
newio.c_cc[VMIN] = 1;
if( tcsetattr( fd, TCSANOW, &newio ) < 0 ) {
    /* Error checking */
}

Вышеуказанные настройки те же, что и в моей библиотеке C и Java * , если вы не хотите настраивать последовательный порт самостоятельно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...