Создание блокировки чтения () из UART в Linux - PullRequest
0 голосов
/ 16 мая 2018

Я пытаюсь записать в последовательный порт (отправив рукопожатие), а затем впоследствии пытаюсь прочитать последовательный порт. При чтении порта я замечаю, что получаю чтение мусора (даже если к линии RX ничего не подключено) или часть строки записи, которую я отправляю в линию TX. Почему я получаю часть этой строки? Я не должен видеть это!

Вот мой код:

   class UART{

    public:
        UART();
        ~UART();
        int open_port();
        int configure_port(); // All port configurations such as parity, baud rate, hardware flow, etc
        int uart_write(std::string);     // Send characters to the serial port
        int uart_read(std::string*, int);            // Read from serial port
        // Close
        void close_port();

    private:
        int fd;

uart.cpp:

UART::UART(){
    open_port();
    configure_port();
}

UART::~UART(){
    close_port();
}

int UART::open_port()
{
    // Open ttys4
    fd = open("/dev/ttyS4", O_RDWR | O_NOCTTY | O_NDELAY);

    if(fd == -1) // if open is unsucessful
    {
        //perror("open_port: Unable to open /dev/ttyS0 - ");
        printf("open_port: Unable to open /dev/ttyS4. \n");
    }
    else
    {
        fcntl(fd, F_SETFL, 0);
        printf("port is open.\n");
    }

    return(fd);
} //open_port

// configure the port
int UART::configure_port()      
{
    struct termios port_settings;      // structure to store the port settings in

    cfsetispeed(&port_settings, B9600);    // set baud rates
    cfsetospeed(&port_settings, B9600);

    port_settings.c_cflag &= ~PARENB;    // set no parity, stop bits, data bits
    port_settings.c_cflag &= ~CSTOPB;
    port_settings.c_cflag &= ~CSIZE;
    port_settings.c_cflag |= CS8;
    port_settings.c_cflag |=  CREAD | CLOCAL;     // turn on READ & ignore ctrl lines

    port_settings.c_cc[VTIME]     =   10;                  // n seconds read timeout
    port_settings.c_iflag     &=  ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
    port_settings.c_lflag     &=  ~(ICANON | ECHO | ECHOE | ISIG); // make raw
    port_settings.c_oflag     &=  ~OPOST;              // make raw

    tcsetattr(fd, TCSANOW, &port_settings);    // apply the settings to the port
    return(fd);
} 

 // Write to serial port
int UART::uart_write(string data)  
{
    int buffer_size = data.length();
    char * data_write = new char[data.length()+1];
    strcpy (data_write, data.c_str());

    int n = write(fd, data_write, buffer_size);  //Send data

    usleep(1000);
    tcdrain(fd);

    printf("Wrote the bytes. \n");

    /* Error Handling */
    int status = 0;
    if (n < 0)
    {
         cout << "Error Writing: " << strerror(errno) << endl;
         status = 0;
    }else{
        status = 1;
    }

    delete[] data_write;

    return status;
}

int UART::uart_read(string *data,int buffer_size)
{
    // Buffer
    char * buf = new char[buffer_size+1];

    usleep(1000);
    tcflush(fd, TCIOFLUSH);

    // Read
    /*I NEED THIS PART TO BE BLOCKING*/
    int n = read( fd, buf , buffer_size );

    /* Error Handling */
    if (n < 0)
    {
         cout << "Error reading: " << strerror(errno) << endl;
    }

    // String received
    string data_received(buf,buffer_size);
    *data = data_received;

    delete[] buf;

    cout << "data_received: " << *data << endl;

    // Did we get blank data?
    if( data_received.length() == 0 )
        return 0;
    else
        return 1;
}

основной

int main()
{ 
    UART uart_connection;

    string handshake = "handshake!";
    uart_connection.uart_write(handshake);

    string data;
    string *data_ptr = &data;
    uart_connection.uart_read(data_ptr );

    cout << data << endl;

}

При печати полученных данных я обычно получаю часть отправленных данных. Итак, на cout << data << endl я получаю следующее: </p>

dshake

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

В частности, я хочу, чтобы int n = read (fd, buf, buffer_size); была блокирующей функцией, которой, по-видимому, не происходит ... Она просто проходит и возвращает кучу странных символов или он читает часть строки, отправленной с записью.

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

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

1 Ответ

0 голосов
/ 16 мая 2018

Read всегда разрешено читать меньше, чем вы просили. Чтобы сделать его «заблокированным» до тех пор, пока вы не прочитаете достаточно символов, вам нужно заключить его в цикл и вызывать до тех пор, пока вы не прочитаете столько байтов, сколько хотите.

В вашем коде n - это количество байтов, которые были успешно прочитаны. Вы только проверяете, что оно неотрицательно.

Цикл, вероятно, будет выглядеть так:

size_t read_count = 0;
while (read_count < buffer_size)
{
    ssize_t read_result = read(fd, buf + read_count, buffer_size - read_count);
    if (read_result < 0)
    {
        cout << "Error reading: " << strerror(errno) << endl;
        break;
    }
    read_count += read_result;
}

Обратите внимание, что, вообще говоря, read - это низкоуровневый интерфейс с множеством простых тонкостей. Например, в случае ошибки стоит проверить EINTR и, возможно, несколько других.

Вдобавок ко всему, функции FILE* не имеют этих проблем, и вы можете использовать fdopen и fread, чтобы последовательно получать то, что вы хотите.

Хотя кажется, что у вас еще не было этой проблемы, write имеет такой же набор проблем. Также разрешено записывать меньше байтов, чем вы дали, и это также может быть прервано. Однако это редко случается с небольшими записями.

...