Когда SIGIO срабатывает? - PullRequest
4 голосов
/ 02 июля 2019

Я пытаюсь получить последовательные данные, но не могу определить время.

Когда получаются последовательные данные, когда запускается SIGIO - при получении первого байта данных или когда получен определенный символ (CR, NL ...)?

Настройка последовательного порта данных:

/*  Open serial port.
*   O_RDONLY - Only receive data
*   O_NOCTTY - Leave process control to other 'jobs' for better portability.
*   O_NDELAY - Enable non-blocking read
*/
fd = open(PORT_PATHNAME, O_RDONLY | O_NOCTTY | O_NDELAY);
fd = open(PORT_PATHNAME, O_RDONLY | O_NOCTTY | O_NDELAY);
/* Set process ID, that will receive SIGIO signals for file desc. events */
fcntl (fd, F_SETOWN, getpid());
/* Enable generation of signals */
fcntl (fd, F_SETFL, O_ASYNC);

...

options.c_oflag &= ~OPOST;

/* Set terminal options using the file descriptor */
tcsetattr(fd, TCSANOW, &options);

struct termios options;
tcgetattr(fd, &options);

/* Set baudrate */
options.c_cflag = B115200;

Настройка прерывания сигнала:

/* Add UART handler function */
saio.sa_handler = signal_handler_IO;
/* Non-zero used for calling sighandler on alternative stacks and so on */
saio.sa_flags = 0;
/* Not specified by POSIX -> not in use */
saio.sa_restorer = NULL;
/* Bind SIGIO (async I/O signals) to the defined structure */
int status = sigaction(SIGIO, &saio, NULL);

Ответы [ 2 ]

0 голосов
/ 03 июля 2019

SIGIO запускается, чтобы сообщить вам, что вы можете получать символы .... (это означает, что если вы сделаете системный вызов read(2), вы получите что-то), то есть это означает, что при попытке не будет получен сигнал. читать и данные не готовы для чтения. Как вы прочтете ниже, это не означает, что ваша система не получила никаких символов, это зависит от того, как настроена последовательная линия. Продолжить чтение ...

Ваш вопрос очень интересен, потому что сигнал отправляется только тогда, когда драйвер решает, что вы можете прочитать больше данных, и это может быть:

  • когда вы нажимаете клавишу возврата, если терминал находится в каноническом режиме (приготовленный или линейный режим), пока вы не передадите строку данных (или не нажмете ^D символ), вы не сделаете входной буфер доступен для приложения.

  • когда вы получили VMIN символов в необработанном режиме (если VMIN отличается от 0)

  • , когда VTIME истекло после получения не менее VMIN символов (после установки VMIN, отличного от нуля)

Причина SIGIO заключается в том, что не нужно ждать прибытия символов, чтобы их можно было обработать в обработчике сигналов. Но в этом нет особой пользы, поскольку прерывания носят асинхронный характер, и вам больше не придется помещать эти символы (после некоторой возможной асинхронной обработки) в какой-то буфер. Существует системный вызов select(2) или poll(2), позволяющий вам выбирать между набором входных каналов и активировать его, как только будет доступен какой-либо вход.

Итак, в заключение, ответ: зависит .

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

Подумайте так: Если вы сделаете блокировку read(2), вы в какой-то момент проснетесь, потому что данные доступны, и вы можете получить некоторые данные. Тот же процесс, который пробуждает вас, потому что некоторые данные доступны, уволит вас SIGIO, если вы настроили прием SIGIO с. Никакой магии здесь, это процесс ... если вас разбудит драйвер, потому что ваш read(2) больше не ждет, тот же драйвер отправит вам сигнал, но только если вы решили не игнорировать его.

0 голосов
/ 02 июля 2019

SIGIO должен сработать, как только вы получите байт данных.

Это минимальный пример, протестированный на Linux с драйвером ftdi_sio:

  #include <stdio.h>
  #include <stdlib.h>
  #include <fcntl.h>
  #include <time.h>
  #include <unistd.h>
  #include <termios.h>
  #include <errno.h>
  #include <string.h>
  #include <sys/types.h>
  #include <sys/uio.h>
  #include <signal.h>      
  #include <termios.h>     
  #include <unistd.h>     

  #define tty   "/dev/ttyUSB0"
  #define baudrate  B9600



  void byteCallback(int status);      // interrupt function 



  int main(){

    int ttyDev = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK);

    if (!ttyDev)
    {
      printf("couldn't open serial device");
      return -1;
    }
    struct sigaction byteAction;      // set the serial interrupt handler
    struct termios oldtio, newtio; 
    //create signal handler
    byteAction.sa_handler = byteCallback;
    sigemptyset(&byteAction.sa_mask); //sa_mask = 0
    byteAction.sa_flags = SA_RESTART;
    sigaction(SIGIO, &byteAction, NULL);

    //Allow process to detect SIGIO
    fcntl(ttyDev, F_SETOWN, getpid());
        fcntl(ttyDev, F_SETFL, FASYNC);


    tcgetattr(ttyDev, &oldtio); //backup current settings
    newtio.c_cflag = baudrate | CS8 | CLOCAL | CREAD;
    newtio.c_cflag &= ~CRTSCTS; //disable hw flow control
    newtio.c_iflag &= ~(IXON | IXOFF | IXANY); //disable flow control
    newtio.c_iflag |= IGNPAR; //ignore parity
    newtio.c_oflag = 0;
    newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); //raw mode
    newtio.c_cc[VMIN] = 1; 
    newtio.c_cc[VTIME] = 0;
    tcflush(ttyDev, TCIFLUSH);
    tcsetattr(ttyDev, TCSANOW, &newtio);

        while(1){
            //Wait for SIGIO to fire
        }

  }

  void byteCallback(int status){
        printf("SIGIO fired!\r\n");


  }

См. Также этот вопрос

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