Не могу прочитать с последовательного порта в Linux - PullRequest
0 голосов
/ 18 октября 2019

Я запрограммировал плату (процессор ERC 32) на возврат символа каждый раз, когда отправляю один символ из последовательного порта. Когда я отправляю персонажа через GTKterm, все работает нормально, и доски возвращаются правильно. Я пишу код на C для отправки и возврата символов;тем не менее, он либо дает сбой, либо работает для некоторых исполнений, и внезапно перестает работать. Я прочитал много вопросов о последовательных портах и ​​не мог понять, что происходит.

Я попробовал 3 подхода:

1) Блокировка кода чтения / записи
Проблема: сработалона некоторое время функция чтения заблокировалась и не заняла ни одного байта. код ниже

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
#include <sys/types.h>

//Test chars
char d='a',a;

int main()

{
    struct          termios tio;
    struct          termios old_tio;

    //Open serial port
    tty_fd=open("/dev/ttyS1",O_RDWR | O_NOCTTY);

    //Just to check, ir returs 3 always
    printf("fd: %d\n",tty_fd);

    //Get previous configurations
    tcgetattr(tty_fd,&old_tio);

    cfsetospeed(&tio,B19200);            // 19200 baud
    cfsetispeed(&tio,B19200);

     /*CS8     : 8n1 (8bit,no parity,1 stopbit)
     CLOCAL  : local connection, no modem contol
     CREAD   : enable receiving characters*/

    tio.c_iflag &= ~(IXON | IXOFF | IXANY);
    tio.c_oflag = 0;

    tio.c_cflag &= ~PARENB;   /* Disables the Parity Enable bit(PARENB),So No Parity   */
    tio.c_cflag &= ~CSTOPB;   /* CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit */
    tio.c_cflag &= ~CSIZE;   /* Clears the mask for setting the data size             */
    tio.c_cflag |=  CS8|CREAD|CLOCAL;
    tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); //non-cannonical

    tio.c_cc[VMIN]=1;
    tio.c_cc[VTIME]=0;

    tcsetattr(tty_fd,TCSANOW,&tio);
    tcflush(tty_fd, TCIFLUSH);
    tcflush(tty_fd, TCOFLUSH);

    //Write a char and waits for a return char immediately after
    bytes_written=write(tty_fd,&d,1);
    printf("bytes written:%d\n",bytes_written);
    read(tty_fd,&a,1);
    printf(" bytes read:%d\n",bytes_read);

    tcsetattr(tty_fd,TCSANOW,&old_tio);
    close(tty_fd);
    return 0;

}

2) Блокировка многопотокового чтения / записи код
Проблема: функциональные блоки чтения и не берут никаких байтов.
Примечание: Я запрограммирован таким образом, что поток чтениясначала инициализируется, чтобы убедиться, что он начинает «наблюдать» за портом независимо от любого вызова записи. Код ниже

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <pthread.h>

char a='z';
char read_char='?';

void *read_thread(void *arg)
{

     int *tty_fd_ptr= (int*) arg;
    int tty_fd = *tty_fd_ptr;

    unsigned int bytes_read=0;

    //Read until it gets at leats one byte
    while(bytes_read<=0)
    {
        bytes_read=read(tty_fd,&read_char,1);
    }

    printf("char: %c\n",read_char);

    pthread_exit(0);

}


void *test_thread(void *arg)
{

    int *tty_fd_ptr= (int*) arg;
    int tty_fd = *tty_fd_ptr;
    unsigned int bytes_written;

    bytes_written=write(tty_fd,&a,1);
    printf("Bytes written: %d\n",bytes_written);

    pthread_exit(0);

}

int main ()

{

    int count;
    int tty_fd;

    //The port oppening routine and configurations is exactly the same of the
    //previous code

     //Thread ID
     pthread_t tid,tid_2;

     //Create attributes
     pthread_attr_t attr,attr_2;

     pthread_attr_init(&attr);
     pthread_create(&tid, &attr,read_thread,&tty_fd);

     pthread_attr_init(&attr_2);
     pthread_create(&tid_2, &attr_2,test_thread,&tty_fd);


     pthread_join(tid,NULL);
     pthread_join(tid_2,NULL);


    tcsetattr(tty_fd,TCSANOW,&old_tio);
    close(tty_fd);
    return 0;

}

3) Неблокируемый код чтения / записи с обработчиком сигнала
Проблема: Как вы можете видеть из кода, я помещаю вызов записи перед основным циклом (цикл наблюдателя порта). Также обработчик сигнала для порта уже установлен. Он пишет, но ничего не читает. Код ниже

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
#include <sys/types.h>

volatile int STOP=FALSE;
int tty_fd;
int bytes_written=0,bytes_read;
char a='z',c='b';

void signal_handler_IO (int status)
     {
        printf("Interrupt\n");
        wait_flag = FALSE;
     }

int main ()

{

    struct sigaction saio;           /* definition of signal action */

    struct termios tio;
    struct termios old_tio;

    tty_fd=open("/dev/ttyS1",O_RDWR | O_NOCTTY | O_NONBLOCK);
    printf("fd: %d\n",tty_fd);

    /* install the signal handler before making the device asynchronous */
     saio.sa_handler = signal_handler_IO;
     sigemptyset(&saio.sa_mask);
     saio.sa_flags = 0;
     saio.sa_restorer = NULL;
     sigaction(SIGIO,&saio,NULL);

     /* allow the process to receive SIGIO */
    fcntl_status=fcntl(tty_fd, F_SETOWN, getpid());

    fcntl_status=fcntl(tty_fd, F_SETFL, FASYNC);

    tcgetattr(tty_fd,&old_tio);

    cfsetospeed(&tio,B19200);            // 19200 baud
    cfsetispeed(&tio,B19200);
    //cfmakeraw(&tio);

     /*CS8     : 8n1 (8bit,no parity,1 stopbit)
     CLOCAL  : local connection, no modem contol
     CREAD   : enable receiving characters*/

    tio.c_iflag &= ~(IXON | IXOFF | IXANY);

    tio.c_oflag=0;

    //tio.c_cflag=CS8|CREAD|CLOCAL;
    tio.c_cflag &= ~PARENB;   /* Disables the Parity Enable bit(PARENB),So No Parity   */
    tio.c_cflag &= ~CSTOPB;   /* CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit */
    tio.c_cflag &= ~CSIZE;   /* Clears the mask for setting the data size             */
    tio.c_cflag |=  CS8|CREAD|CLOCAL;
    tio.c_lflag=0;


    tio.c_cc[VMIN]=1;
    tio.c_cc[VTIME]=0;

    tcsetattr(tty_fd,TCSANOW,&tio);
    tcflush(tty_fd, TCIFLUSH);
    tcflush(tty_fd, TCOFLUSH);

     bytes_written=write(tty_fd,&c,1);
     printf("bytes written: %d\n",bytes_written);


     while (STOP==FALSE)
      {
              usleep(10000);

              /* after receiving SIGIO, wait_flag = FALSE, input is available
                 and can be read */
         if (wait_flag==FALSE)
         {


            bytes_read=read(tty_fd,&a,1);

            printf("bytes read:%d \n",bytes_read);
             wait_flag = TRUE;      /* wait for new input */
         }
       }

    tcsetattr(tty_fd,TCSANOW,&old_tio);
    close(tty_fd);
    return 0;

}

Моя цель - сделать аппаратное обеспечение в системе циклов, где передаваемые данные начинаются со стороны Linux, проходят через UART к плате, плата принимает данные, обрабатывает иверните его на компьютер, и затем цикл снова запустится, пока не будет выполнено какое-либо условие остановки. Я написал простой код для доски, просто чтобы проверить односимвольный цикл, прежде чем увеличивать сложность.

Стоит отметить, что:
-> если я пишу простой код, который просто вызывает одинФункция записи с одним символом и выполняет GTKterm в то же время я вижу ответ платы в консоли GTKterm.
-> для блокирующих версий кода, когда код блокируется в функции чтения, Если я сбросил плату, топринимает первый символ приветственного сообщения на плате. Это ожидаемо, но я не знаю, почему для запрограммированных на плате вызовов записи это не занимает, но GTkterm делает.
-> Я также попробовал некоторые коды впрямая машина Linux и те же проблемы, и GTKterm работает нормально.

Я не уверен, что есть более хитрая настройка, которую я не вижу. Буду признателен за любую помощь.

Плата: чип ERC32 (TSC695F), программируемый операционной системой реального времени RTEMS. Чип UART является дуплексным.

Компьютер: Mandriva linux на виртуальной машине VMware через Windows 7.

$ uname -a
Linux localhost.localdomain 2.6. 36.2-desktop586-2mnb # 1 SMP Ср 22 декабря 17:11:08 UTC 2010 i686 i686 i386 GNU / Linux

$ cat / etc / * - выпуск
Mandriva Linux выпуск 2010.2 (официальный) для i586

...